| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.809 2021/02/14 12:16:13 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.810 2021/02/14 12:24:53 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. |
| @@ -129,27 +129,27 @@ | | | @@ -129,27 +129,27 @@ |
129 | #include <regex.h> | | 129 | #include <regex.h> |
130 | #endif | | 130 | #endif |
131 | #include <errno.h> | | 131 | #include <errno.h> |
132 | #include <inttypes.h> | | 132 | #include <inttypes.h> |
133 | #include <limits.h> | | 133 | #include <limits.h> |
134 | #include <time.h> | | 134 | #include <time.h> |
135 | | | 135 | |
136 | #include "make.h" | | 136 | #include "make.h" |
137 | #include "dir.h" | | 137 | #include "dir.h" |
138 | #include "job.h" | | 138 | #include "job.h" |
139 | #include "metachar.h" | | 139 | #include "metachar.h" |
140 | | | 140 | |
141 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 141 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
142 | MAKE_RCSID("$NetBSD: var.c,v 1.809 2021/02/14 12:16:13 rillig Exp $"); | | 142 | MAKE_RCSID("$NetBSD: var.c,v 1.810 2021/02/14 12:24:53 rillig Exp $"); |
143 | | | 143 | |
144 | typedef enum VarFlags { | | 144 | typedef enum VarFlags { |
145 | VAR_NONE = 0, | | 145 | VAR_NONE = 0, |
146 | | | 146 | |
147 | /* | | 147 | /* |
148 | * The variable's value is currently being used by Var_Parse or | | 148 | * The variable's value is currently being used by Var_Parse or |
149 | * Var_Subst. This marker is used to avoid endless recursion. | | 149 | * Var_Subst. This marker is used to avoid endless recursion. |
150 | */ | | 150 | */ |
151 | VAR_IN_USE = 0x01, | | 151 | VAR_IN_USE = 0x01, |
152 | | | 152 | |
153 | /* | | 153 | /* |
154 | * The variable comes from the environment. | | 154 | * The variable comes from the environment. |
155 | * These variables are not registered in any GNode, therefore they | | 155 | * These variables are not registered in any GNode, therefore they |
| @@ -2988,112 +2988,108 @@ static ApplyModifierResult | | | @@ -2988,112 +2988,108 @@ static ApplyModifierResult |
2988 | ApplyModifier_To(const char **pp, const char *val, ApplyModifiersState *st) | | 2988 | ApplyModifier_To(const char **pp, const char *val, ApplyModifiersState *st) |
2989 | { | | 2989 | { |
2990 | const char *mod = *pp; | | 2990 | const char *mod = *pp; |
2991 | assert(mod[0] == 't'); | | 2991 | assert(mod[0] == 't'); |
2992 | | | 2992 | |
2993 | if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { | | 2993 | if (mod[1] == st->endc || mod[1] == ':' || mod[1] == '\0') { |
2994 | *pp = mod + 1; | | 2994 | *pp = mod + 1; |
2995 | return AMR_BAD; /* Found ":t<endc>" or ":t:". */ | | 2995 | return AMR_BAD; /* Found ":t<endc>" or ":t:". */ |
2996 | } | | 2996 | } |
2997 | | | 2997 | |
2998 | if (mod[1] == 's') | | 2998 | if (mod[1] == 's') |
2999 | return ApplyModifier_ToSep(pp, val, st); | | 2999 | return ApplyModifier_ToSep(pp, val, st); |
3000 | | | 3000 | |
3001 | if (mod[2] != st->endc && mod[2] != ':') { | | 3001 | if (mod[2] != st->endc && mod[2] != ':') { /* :t<unrecognized> */ |
3002 | *pp = mod + 1; | | 3002 | *pp = mod + 1; |
3003 | return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ | | 3003 | return AMR_BAD; |
3004 | } | | 3004 | } |
3005 | | | 3005 | |
3006 | /* Check for two-character options: ":tu", ":tl" */ | | 3006 | if (mod[1] == 'A') { /* :tA */ |
3007 | if (mod[1] == 'A') { /* absolute path */ | | | |
3008 | st->newVal = FStr_InitOwn( | | 3007 | st->newVal = FStr_InitOwn( |
3009 | ModifyWords(val, ModifyWord_Realpath, NULL, | | 3008 | ModifyWords(val, ModifyWord_Realpath, NULL, |
3010 | st->oneBigWord, st->sep)); | | 3009 | st->oneBigWord, st->sep)); |
3011 | *pp = mod + 2; | | 3010 | *pp = mod + 2; |
3012 | return AMR_OK; | | 3011 | return AMR_OK; |
3013 | } | | 3012 | } |
3014 | | | 3013 | |
3015 | if (mod[1] == 'u') { /* :tu */ | | 3014 | if (mod[1] == 'u') { /* :tu */ |
3016 | st->newVal = FStr_InitOwn(str_toupper(val)); | | 3015 | st->newVal = FStr_InitOwn(str_toupper(val)); |
3017 | *pp = mod + 2; | | 3016 | *pp = mod + 2; |
3018 | return AMR_OK; | | 3017 | return AMR_OK; |
3019 | } | | 3018 | } |
3020 | | | 3019 | |
3021 | if (mod[1] == 'l') { /* :tl */ | | 3020 | if (mod[1] == 'l') { /* :tl */ |
3022 | st->newVal = FStr_InitOwn(str_tolower(val)); | | 3021 | st->newVal = FStr_InitOwn(str_tolower(val)); |
3023 | *pp = mod + 2; | | 3022 | *pp = mod + 2; |
3024 | return AMR_OK; | | 3023 | return AMR_OK; |
3025 | } | | 3024 | } |
3026 | | | 3025 | |
3027 | if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ | | 3026 | if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ |
3028 | st->oneBigWord = mod[1] == 'W'; | | 3027 | st->oneBigWord = mod[1] == 'W'; |
3029 | st->newVal = FStr_InitRefer(val); | | 3028 | st->newVal = FStr_InitRefer(val); |
3030 | *pp = mod + 2; | | 3029 | *pp = mod + 2; |
3031 | return AMR_OK; | | 3030 | return AMR_OK; |
3032 | } | | 3031 | } |
3033 | | | 3032 | |
3034 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ | | 3033 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ |
3035 | *pp = mod + 1; | | 3034 | *pp = mod + 1; |
3036 | return AMR_BAD; | | 3035 | return AMR_BAD; |
3037 | } | | 3036 | } |
3038 | | | 3037 | |
3039 | /* :[#], :[1], :[-1..1], etc. */ | | 3038 | /* :[#], :[1], :[-1..1], etc. */ |
3040 | static ApplyModifierResult | | 3039 | static ApplyModifierResult |
3041 | ApplyModifier_Words(const char **pp, const char *val, ApplyModifiersState *st) | | 3040 | ApplyModifier_Words(const char **pp, const char *val, ApplyModifiersState *st) |
3042 | { | | 3041 | { |
3043 | char *estr; | | 3042 | char *estr; |
3044 | int first, last; | | 3043 | int first, last; |
3045 | VarParseResult res; | | 3044 | VarParseResult res; |
3046 | const char *p; | | 3045 | const char *p; |
3047 | | | 3046 | |
3048 | (*pp)++; /* skip the '[' */ | | 3047 | (*pp)++; /* skip the '[' */ |
3049 | res = ParseModifierPart(pp, ']', st->eflags, st, &estr); | | 3048 | res = ParseModifierPart(pp, ']', st->eflags, st, &estr); |
3050 | if (res != VPR_OK) | | 3049 | if (res != VPR_OK) |
3051 | return AMR_CLEANUP; | | 3050 | return AMR_CLEANUP; |
3052 | | | 3051 | |
3053 | /* now *pp points just after the closing ']' */ | | | |
3054 | if (**pp != ':' && **pp != st->endc) | | 3052 | if (**pp != ':' && **pp != st->endc) |
3055 | goto bad_modifier; /* Found junk after ']' */ | | 3053 | goto bad_modifier; /* Found junk after ']' */ |
3056 | | | 3054 | |
3057 | if (estr[0] == '\0') | | 3055 | if (estr[0] == '\0') |
3058 | goto bad_modifier; /* empty square brackets in ":[]". */ | | 3056 | goto bad_modifier; /* Found ":[]". */ |
3059 | | | 3057 | |
3060 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ | | 3058 | if (estr[0] == '#' && estr[1] == '\0') { /* Found ":[#]" */ |
3061 | if (st->oneBigWord) { | | 3059 | if (st->oneBigWord) { |
3062 | st->newVal = FStr_InitRefer("1"); | | 3060 | st->newVal = FStr_InitRefer("1"); |
3063 | } else { | | 3061 | } else { |
3064 | Buffer buf; | | 3062 | Buffer buf; |
3065 | | | 3063 | |
3066 | Words words = Str_Words(val, FALSE); | | 3064 | Words words = Str_Words(val, FALSE); |
3067 | size_t ac = words.len; | | 3065 | size_t ac = words.len; |
3068 | Words_Free(words); | | 3066 | Words_Free(words); |
3069 | | | 3067 | |
3070 | /* 3 digits + '\0' is usually enough */ | | 3068 | /* 3 digits + '\0' is usually enough */ |
3071 | Buf_InitSize(&buf, 4); | | 3069 | Buf_InitSize(&buf, 4); |
3072 | Buf_AddInt(&buf, (int)ac); | | 3070 | Buf_AddInt(&buf, (int)ac); |
3073 | st->newVal = FStr_InitOwn(Buf_DoneData(&buf)); | | 3071 | st->newVal = FStr_InitOwn(Buf_DoneData(&buf)); |
3074 | } | | 3072 | } |
3075 | goto ok; | | 3073 | goto ok; |
3076 | } | | 3074 | } |
3077 | | | 3075 | |
3078 | if (estr[0] == '*' && estr[1] == '\0') { | | 3076 | if (estr[0] == '*' && estr[1] == '\0') { /* Found ":[*]" */ |
3079 | /* Found ":[*]" */ | | | |
3080 | st->oneBigWord = TRUE; | | 3077 | st->oneBigWord = TRUE; |
3081 | st->newVal = FStr_InitRefer(val); | | 3078 | st->newVal = FStr_InitRefer(val); |
3082 | goto ok; | | 3079 | goto ok; |
3083 | } | | 3080 | } |
3084 | | | 3081 | |
3085 | if (estr[0] == '@' && estr[1] == '\0') { | | 3082 | if (estr[0] == '@' && estr[1] == '\0') { /* Found ":[@]" */ |
3086 | /* Found ":[@]" */ | | | |
3087 | st->oneBigWord = FALSE; | | 3083 | st->oneBigWord = FALSE; |
3088 | st->newVal = FStr_InitRefer(val); | | 3084 | st->newVal = FStr_InitRefer(val); |
3089 | goto ok; | | 3085 | goto ok; |
3090 | } | | 3086 | } |
3091 | | | 3087 | |
3092 | /* | | 3088 | /* |
3093 | * We expect estr to contain a single integer for :[N], or two | | 3089 | * We expect estr to contain a single integer for :[N], or two |
3094 | * integers separated by ".." for :[start..end]. | | 3090 | * integers separated by ".." for :[start..end]. |
3095 | */ | | 3091 | */ |
3096 | p = estr; | | 3092 | p = estr; |
3097 | if (!TryParseIntBase0(&p, &first)) | | 3093 | if (!TryParseIntBase0(&p, &first)) |
3098 | goto bad_modifier; /* Found junk instead of a number */ | | 3094 | goto bad_modifier; /* Found junk instead of a number */ |
3099 | | | 3095 | |