| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.640 2020/11/01 22:48:41 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.641 2020/11/01 23:17:40 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. |
| @@ -120,27 +120,27 @@ | | | @@ -120,27 +120,27 @@ |
120 | #include <regex.h> | | 120 | #include <regex.h> |
121 | #endif | | 121 | #endif |
122 | #include <errno.h> | | 122 | #include <errno.h> |
123 | #include <inttypes.h> | | 123 | #include <inttypes.h> |
124 | #include <limits.h> | | 124 | #include <limits.h> |
125 | #include <time.h> | | 125 | #include <time.h> |
126 | | | 126 | |
127 | #include "make.h" | | 127 | #include "make.h" |
128 | #include "dir.h" | | 128 | #include "dir.h" |
129 | #include "job.h" | | 129 | #include "job.h" |
130 | #include "metachar.h" | | 130 | #include "metachar.h" |
131 | | | 131 | |
132 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 132 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
133 | MAKE_RCSID("$NetBSD: var.c,v 1.640 2020/11/01 22:48:41 rillig Exp $"); | | 133 | MAKE_RCSID("$NetBSD: var.c,v 1.641 2020/11/01 23:17:40 rillig Exp $"); |
134 | | | 134 | |
135 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) | | 135 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) |
136 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) | | 136 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) |
137 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) | | 137 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) |
138 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) | | 138 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) |
139 | | | 139 | |
140 | ENUM_FLAGS_RTTI_3(VarEvalFlags, | | 140 | ENUM_FLAGS_RTTI_3(VarEvalFlags, |
141 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); | | 141 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); |
142 | | | 142 | |
143 | /* | | 143 | /* |
144 | * This lets us tell if we have replaced the original environ | | 144 | * This lets us tell if we have replaced the original environ |
145 | * (which we cannot free). | | 145 | * (which we cannot free). |
146 | */ | | 146 | */ |
| @@ -3244,26 +3244,103 @@ ApplyModifier(const char **pp, ApplyModi | | | @@ -3244,26 +3244,103 @@ ApplyModifier(const char **pp, ApplyModi |
3244 | case 'O': | | 3244 | case 'O': |
3245 | return ApplyModifier_Order(pp, st); | | 3245 | return ApplyModifier_Order(pp, st); |
3246 | case 'u': | | 3246 | case 'u': |
3247 | return ApplyModifier_Unique(pp, st); | | 3247 | return ApplyModifier_Unique(pp, st); |
3248 | #ifdef SUNSHCMD | | 3248 | #ifdef SUNSHCMD |
3249 | case 's': | | 3249 | case 's': |
3250 | return ApplyModifier_SunShell(pp, st); | | 3250 | return ApplyModifier_SunShell(pp, st); |
3251 | #endif | | 3251 | #endif |
3252 | default: | | 3252 | default: |
3253 | return AMR_UNKNOWN; | | 3253 | return AMR_UNKNOWN; |
3254 | } | | 3254 | } |
3255 | } | | 3255 | } |
3256 | | | 3256 | |
| | | 3257 | static char *ApplyModifiers(const char **, char *, char, char, Var *, |
| | | 3258 | VarExprFlags *, GNode *, VarEvalFlags, void **); |
| | | 3259 | |
| | | 3260 | typedef enum ApplyModifiersIndirectResult { |
| | | 3261 | AMIR_CONTINUE, |
| | | 3262 | AMIR_APPLY_MODS, |
| | | 3263 | AMIR_OUT |
| | | 3264 | } ApplyModifiersIndirectResult; |
| | | 3265 | |
| | | 3266 | /* While expanding a variable expression, expand and apply indirect |
| | | 3267 | * modifiers. */ |
| | | 3268 | static ApplyModifiersIndirectResult |
| | | 3269 | ApplyModifiersIndirect( |
| | | 3270 | ApplyModifiersState *const st, |
| | | 3271 | const char **inout_p, |
| | | 3272 | void **const out_freeIt |
| | | 3273 | ) { |
| | | 3274 | const char *p = *inout_p; |
| | | 3275 | const char *nested_p = p; |
| | | 3276 | void *freeIt; |
| | | 3277 | const char *rval; |
| | | 3278 | char c; |
| | | 3279 | |
| | | 3280 | (void)Var_Parse(&nested_p, st->ctxt, st->eflags, &rval, &freeIt); |
| | | 3281 | /* TODO: handle errors */ |
| | | 3282 | |
| | | 3283 | /* |
| | | 3284 | * If we have not parsed up to st->endc or ':', we are not |
| | | 3285 | * interested. This means the expression ${VAR:${M_1}${M_2}} |
| | | 3286 | * is not accepted, but ${VAR:${M_1}:${M_2}} is. |
| | | 3287 | */ |
| | | 3288 | if (rval[0] != '\0' && |
| | | 3289 | (c = *nested_p) != '\0' && c != ':' && c != st->endc) { |
| | | 3290 | if (DEBUG(LINT)) |
| | | 3291 | Parse_Error(PARSE_FATAL, |
| | | 3292 | "Missing delimiter ':' after indirect modifier \"%.*s\"", |
| | | 3293 | (int)(nested_p - p), p); |
| | | 3294 | |
| | | 3295 | free(freeIt); |
| | | 3296 | /* XXX: apply_mods doesn't sound like "not interested". */ |
| | | 3297 | /* XXX: Why is the indirect modifier parsed again by |
| | | 3298 | * apply_mods? If any, p should be advanced to nested_p. */ |
| | | 3299 | return AMIR_APPLY_MODS; |
| | | 3300 | } |
| | | 3301 | |
| | | 3302 | VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", |
| | | 3303 | rval, (int)(size_t)(nested_p - p), p); |
| | | 3304 | |
| | | 3305 | p = nested_p; |
| | | 3306 | |
| | | 3307 | if (rval[0] != '\0') { |
| | | 3308 | const char *rval_pp = rval; |
| | | 3309 | st->val = ApplyModifiers(&rval_pp, st->val, '\0', '\0', st->v, |
| | | 3310 | &st->exprFlags, st->ctxt, st->eflags, out_freeIt); |
| | | 3311 | if (st->val == var_Error |
| | | 3312 | || (st->val == varUndefined && !(st->eflags & VARE_UNDEFERR)) |
| | | 3313 | || *rval_pp != '\0') { |
| | | 3314 | free(freeIt); |
| | | 3315 | *inout_p = p; |
| | | 3316 | return AMIR_OUT; /* error already reported */ |
| | | 3317 | } |
| | | 3318 | } |
| | | 3319 | free(freeIt); |
| | | 3320 | |
| | | 3321 | if (*p == ':') |
| | | 3322 | p++; |
| | | 3323 | else if (*p == '\0' && st->endc != '\0') { |
| | | 3324 | Error("Unclosed variable specification after complex " |
| | | 3325 | "modifier (expecting '%c') for %s", st->endc, st->v->name); |
| | | 3326 | *inout_p = p; |
| | | 3327 | return AMIR_OUT; |
| | | 3328 | } |
| | | 3329 | |
| | | 3330 | *inout_p = p; |
| | | 3331 | return AMIR_CONTINUE; |
| | | 3332 | } |
| | | 3333 | |
3257 | /* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ | | 3334 | /* Apply any modifiers (such as :Mpattern or :@var@loop@ or :Q or ::=value). */ |
3258 | static char * | | 3335 | static char * |
3259 | ApplyModifiers( | | 3336 | ApplyModifiers( |
3260 | const char **pp, /* the parsing position, updated upon return */ | | 3337 | const char **pp, /* the parsing position, updated upon return */ |
3261 | char *const val, /* the current value of the expression */ | | 3338 | char *const val, /* the current value of the expression */ |
3262 | char const startc, /* '(' or '{', or '\0' for indirect modifiers */ | | 3339 | char const startc, /* '(' or '{', or '\0' for indirect modifiers */ |
3263 | char const endc, /* ')' or '}', or '\0' for indirect modifiers */ | | 3340 | char const endc, /* ')' or '}', or '\0' for indirect modifiers */ |
3264 | Var * const v, | | 3341 | Var * const v, |
3265 | VarExprFlags *exprFlags, | | 3342 | VarExprFlags *exprFlags, |
3266 | GNode * const ctxt, /* for looking up and modifying variables */ | | 3343 | GNode * const ctxt, /* for looking up and modifying variables */ |
3267 | VarEvalFlags const eflags, | | 3344 | VarEvalFlags const eflags, |
3268 | void ** const out_freeIt /* free this after using the return value */ | | 3345 | void ** const out_freeIt /* free this after using the return value */ |
3269 | ) { | | 3346 | ) { |
| @@ -3277,84 +3354,33 @@ ApplyModifiers( | | | @@ -3277,84 +3354,33 @@ ApplyModifiers( |
3277 | }; | | 3354 | }; |
3278 | const char *p; | | 3355 | const char *p; |
3279 | const char *mod; | | 3356 | const char *mod; |
3280 | ApplyModifierResult res; | | 3357 | ApplyModifierResult res; |
3281 | | | 3358 | |
3282 | assert(startc == '(' || startc == '{' || startc == '\0'); | | 3359 | assert(startc == '(' || startc == '{' || startc == '\0'); |
3283 | assert(endc == ')' || endc == '}' || endc == '\0'); | | 3360 | assert(endc == ')' || endc == '}' || endc == '\0'); |
3284 | assert(val != NULL); | | 3361 | assert(val != NULL); |
3285 | | | 3362 | |
3286 | p = *pp; | | 3363 | p = *pp; |
3287 | while (*p != '\0' && *p != endc) { | | 3364 | while (*p != '\0' && *p != endc) { |
3288 | | | 3365 | |
3289 | if (*p == '$') { | | 3366 | if (*p == '$') { |
3290 | /* | | 3367 | ApplyModifiersIndirectResult amir; |
3291 | * We may have some complex modifiers in a variable. | | 3368 | amir = ApplyModifiersIndirect(&st, &p, out_freeIt); |
3292 | */ | | 3369 | if (amir == AMIR_CONTINUE) |
3293 | const char *nested_p = p; | | 3370 | continue; |
3294 | void *freeIt; | | 3371 | if (amir == AMIR_OUT) |
3295 | const char *rval; | | 3372 | goto out; |
3296 | char c; | | | |
3297 | | | | |
3298 | (void)Var_Parse(&nested_p, st.ctxt, st.eflags, &rval, &freeIt); | | | |
3299 | /* TODO: handle errors */ | | | |
3300 | | | | |
3301 | /* | | | |
3302 | * If we have not parsed up to st.endc or ':', we are not | | | |
3303 | * interested. This means the expression ${VAR:${M_1}${M_2}} | | | |
3304 | * is not accepted, but ${VAR:${M_1}:${M_2}} is. | | | |
3305 | */ | | | |
3306 | if (rval[0] != '\0' && | | | |
3307 | (c = *nested_p) != '\0' && c != ':' && c != st.endc) { | | | |
3308 | if (DEBUG(LINT)) | | | |
3309 | Parse_Error(PARSE_FATAL, | | | |
3310 | "Missing delimiter ':' after indirect modifier \"%.*s\"", | | | |
3311 | (int)(nested_p - p), p); | | | |
3312 | | | | |
3313 | free(freeIt); | | | |
3314 | /* XXX: apply_mods doesn't sound like "not interested". */ | | | |
3315 | /* XXX: Why is the indirect modifier parsed again by | | | |
3316 | * apply_mods? If any, p should be advanced to nested_p. */ | | | |
3317 | goto apply_mods; | | | |
3318 | } | | | |
3319 | | | | |
3320 | VAR_DEBUG3("Indirect modifier \"%s\" from \"%.*s\"\n", | | | |
3321 | rval, (int)(size_t)(nested_p - p), p); | | | |
3322 | | | | |
3323 | p = nested_p; | | | |
3324 | | | | |
3325 | if (rval[0] != '\0') { | | | |
3326 | const char *rval_pp = rval; | | | |
3327 | st.val = ApplyModifiers(&rval_pp, st.val, '\0', '\0', v, | | | |
3328 | &st.exprFlags, ctxt, eflags, out_freeIt); | | | |
3329 | if (st.val == var_Error | | | |
3330 | || (st.val == varUndefined && !(st.eflags & VARE_UNDEFERR)) | | | |
3331 | || *rval_pp != '\0') { | | | |
3332 | free(freeIt); | | | |
3333 | goto out; /* error already reported */ | | | |
3334 | } | | | |
3335 | } | | | |
3336 | free(freeIt); | | | |
3337 | | | | |
3338 | if (*p == ':') | | | |
3339 | p++; | | | |
3340 | else if (*p == '\0' && endc != '\0') { | | | |
3341 | Error("Unclosed variable specification after complex " | | | |
3342 | "modifier (expecting '%c') for %s", st.endc, st.v->name); | | | |
3343 | goto out; | | | |
3344 | } | | | |
3345 | continue; | | | |
3346 | } | | 3373 | } |
3347 | apply_mods: | | | |
3348 | st.newVal = var_Error; /* default value, in case of errors */ | | 3374 | st.newVal = var_Error; /* default value, in case of errors */ |
3349 | mod = p; | | 3375 | mod = p; |
3350 | | | 3376 | |
3351 | if (DEBUG(VAR)) | | 3377 | if (DEBUG(VAR)) |
3352 | LogBeforeApply(&st, mod, endc); | | 3378 | LogBeforeApply(&st, mod, endc); |
3353 | | | 3379 | |
3354 | res = ApplyModifier(&p, &st); | | 3380 | res = ApplyModifier(&p, &st); |
3355 | | | 3381 | |
3356 | #ifdef SYSVVARSUB | | 3382 | #ifdef SYSVVARSUB |
3357 | if (res == AMR_UNKNOWN) { | | 3383 | if (res == AMR_UNKNOWN) { |
3358 | assert(p == mod); | | 3384 | assert(p == mod); |
3359 | res = ApplyModifier_SysV(&p, &st); | | 3385 | res = ApplyModifier_SysV(&p, &st); |
3360 | } | | 3386 | } |