| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.1102 2024/04/20 10:18:55 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.1103 2024/04/21 08:56:49 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -127,27 +127,27 @@ | | | @@ -127,27 +127,27 @@ |
127 | #include <sys/types.h> | | 127 | #include <sys/types.h> |
128 | #include <regex.h> | | 128 | #include <regex.h> |
129 | #include <errno.h> | | 129 | #include <errno.h> |
130 | #include <inttypes.h> | | 130 | #include <inttypes.h> |
131 | #include <limits.h> | | 131 | #include <limits.h> |
132 | #include <time.h> | | 132 | #include <time.h> |
133 | | | 133 | |
134 | #include "make.h" | | 134 | #include "make.h" |
135 | #include "dir.h" | | 135 | #include "dir.h" |
136 | #include "job.h" | | 136 | #include "job.h" |
137 | #include "metachar.h" | | 137 | #include "metachar.h" |
138 | | | 138 | |
139 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 139 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
140 | MAKE_RCSID("$NetBSD: var.c,v 1.1102 2024/04/20 10:18:55 rillig Exp $"); | | 140 | MAKE_RCSID("$NetBSD: var.c,v 1.1103 2024/04/21 08:56:49 rillig Exp $"); |
141 | | | 141 | |
142 | /* | | 142 | /* |
143 | * Variables are defined using one of the VAR=value assignments. Their | | 143 | * Variables are defined using one of the VAR=value assignments. Their |
144 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers | | 144 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers |
145 | * such as ${VAR:S,from,to,g:Q}. | | 145 | * such as ${VAR:S,from,to,g:Q}. |
146 | * | | 146 | * |
147 | * There are 3 kinds of variables: scope variables, environment variables, | | 147 | * There are 3 kinds of variables: scope variables, environment variables, |
148 | * undefined variables. | | 148 | * undefined variables. |
149 | * | | 149 | * |
150 | * Scope variables are stored in a GNode.scope. The only way to undefine | | 150 | * Scope variables are stored in a GNode.scope. The only way to undefine |
151 | * a scope variable is using the .undef directive. In particular, it must | | 151 | * a scope variable is using the .undef directive. In particular, it must |
152 | * not be possible to undefine a variable during the evaluation of an | | 152 | * not be possible to undefine a variable during the evaluation of an |
153 | * expression, or Var.name might point nowhere. (There is another, | | 153 | * expression, or Var.name might point nowhere. (There is another, |
| @@ -2505,50 +2505,69 @@ TryParseTime(const char **pp, time_t *ou | | | @@ -2505,50 +2505,69 @@ TryParseTime(const char **pp, time_t *ou |
2505 | if (!ch_isdigit(**pp)) | | 2505 | if (!ch_isdigit(**pp)) |
2506 | return false; | | 2506 | return false; |
2507 | | | 2507 | |
2508 | errno = 0; | | 2508 | errno = 0; |
2509 | n = strtoul(*pp, &end, 10); | | 2509 | n = strtoul(*pp, &end, 10); |
2510 | if (n == ULONG_MAX && errno == ERANGE) | | 2510 | if (n == ULONG_MAX && errno == ERANGE) |
2511 | return false; | | 2511 | return false; |
2512 | | | 2512 | |
2513 | *pp = end; | | 2513 | *pp = end; |
2514 | *out_time = (time_t)n; /* ignore possible truncation for now */ | | 2514 | *out_time = (time_t)n; /* ignore possible truncation for now */ |
2515 | return true; | | 2515 | return true; |
2516 | } | | 2516 | } |
2517 | | | 2517 | |
| | | 2518 | static bool |
| | | 2519 | Substring_ParseTime(Substring s, time_t *out_time) |
| | | 2520 | { |
| | | 2521 | const char *p; |
| | | 2522 | unsigned long n; |
| | | 2523 | |
| | | 2524 | n = 0; |
| | | 2525 | for (p = s.start; p != s.end && ch_isdigit(*p); p++) { |
| | | 2526 | unsigned long next = 10 * n + ((unsigned)*p - '0'); |
| | | 2527 | if (next < n) |
| | | 2528 | return false; |
| | | 2529 | n = next; |
| | | 2530 | } |
| | | 2531 | if (p == s.start || p != s.end) |
| | | 2532 | return false; |
| | | 2533 | |
| | | 2534 | *out_time = (time_t)n; /* ignore possible truncation for now */ |
| | | 2535 | return true; |
| | | 2536 | } |
| | | 2537 | |
2518 | /* :gmtime and :localtime */ | | 2538 | /* :gmtime and :localtime */ |
2519 | static ApplyModifierResult | | 2539 | static ApplyModifierResult |
2520 | ApplyModifier_Time(const char **pp, ModChain *ch) | | 2540 | ApplyModifier_Time(const char **pp, ModChain *ch) |
2521 | { | | 2541 | { |
2522 | Expr *expr; | | 2542 | Expr *expr; |
2523 | time_t t; | | 2543 | time_t t; |
2524 | const char *args; | | 2544 | const char *args; |
2525 | const char *mod = *pp; | | 2545 | const char *mod = *pp; |
2526 | bool gmt = mod[0] == 'g'; | | 2546 | bool gmt = mod[0] == 'g'; |
2527 | | | 2547 | |
2528 | if (!ModMatchEq(mod, gmt ? "gmtime" : "localtime", ch)) | | 2548 | if (!ModMatchEq(mod, gmt ? "gmtime" : "localtime", ch)) |
2529 | return AMR_UNKNOWN; | | 2549 | return AMR_UNKNOWN; |
2530 | args = mod + (gmt ? 6 : 9); | | 2550 | args = mod + (gmt ? 6 : 9); |
2531 | | | 2551 | |
2532 | if (args[0] == '=') { | | 2552 | if (args[0] == '=') { |
2533 | const char *p = args + 1; | | 2553 | const char *p = args + 1; |
2534 | LazyBuf buf; | | 2554 | LazyBuf buf; |
2535 | if (!ParseModifierPartSubst(&p, true, '\0', ch->expr->emode, | | 2555 | if (!ParseModifierPartSubst(&p, true, '\0', ch->expr->emode, |
2536 | ch, &buf, NULL, NULL)) | | 2556 | ch, &buf, NULL, NULL)) |
2537 | return AMR_CLEANUP; | | 2557 | return AMR_CLEANUP; |
2538 | if (ModChain_ShouldEval(ch)) { | | 2558 | if (ModChain_ShouldEval(ch)) { |
2539 | Substring arg = LazyBuf_Get(&buf); | | 2559 | Substring arg = LazyBuf_Get(&buf); |
2540 | const char *arg_p = arg.start; | | 2560 | if (!Substring_ParseTime(arg, &t)) { |
2541 | if (!TryParseTime(&arg_p, &t) || arg_p != arg.end) { | | | |
2542 | Parse_Error(PARSE_FATAL, | | 2561 | Parse_Error(PARSE_FATAL, |
2543 | "Invalid time value \"%.*s\"", | | 2562 | "Invalid time value \"%.*s\"", |
2544 | (int)Substring_Length(arg), arg.start); | | 2563 | (int)Substring_Length(arg), arg.start); |
2545 | LazyBuf_Done(&buf); | | 2564 | LazyBuf_Done(&buf); |
2546 | return AMR_CLEANUP; | | 2565 | return AMR_CLEANUP; |
2547 | } | | 2566 | } |
2548 | } else | | 2567 | } else |
2549 | t = 0; | | 2568 | t = 0; |
2550 | LazyBuf_Done(&buf); | | 2569 | LazyBuf_Done(&buf); |
2551 | *pp = p; | | 2570 | *pp = p; |
2552 | } else { | | 2571 | } else { |
2553 | t = 0; | | 2572 | t = 0; |
2554 | *pp = args; | | 2573 | *pp = args; |