| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.863 2021/03/14 15:24:37 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.864 2021/03/14 15:43:31 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. |
| @@ -130,27 +130,27 @@ | | | @@ -130,27 +130,27 @@ |
130 | #include <regex.h> | | 130 | #include <regex.h> |
131 | #endif | | 131 | #endif |
132 | #include <errno.h> | | 132 | #include <errno.h> |
133 | #include <inttypes.h> | | 133 | #include <inttypes.h> |
134 | #include <limits.h> | | 134 | #include <limits.h> |
135 | #include <time.h> | | 135 | #include <time.h> |
136 | | | 136 | |
137 | #include "make.h" | | 137 | #include "make.h" |
138 | #include "dir.h" | | 138 | #include "dir.h" |
139 | #include "job.h" | | 139 | #include "job.h" |
140 | #include "metachar.h" | | 140 | #include "metachar.h" |
141 | | | 141 | |
142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 142 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
143 | MAKE_RCSID("$NetBSD: var.c,v 1.863 2021/03/14 15:24:37 rillig Exp $"); | | 143 | MAKE_RCSID("$NetBSD: var.c,v 1.864 2021/03/14 15:43:31 rillig Exp $"); |
144 | | | 144 | |
145 | typedef enum VarFlags { | | 145 | typedef enum VarFlags { |
146 | VFL_NONE = 0, | | 146 | VFL_NONE = 0, |
147 | | | 147 | |
148 | /* | | 148 | /* |
149 | * The variable's value is currently being used by Var_Parse or | | 149 | * The variable's value is currently being used by Var_Parse or |
150 | * Var_Subst. This marker is used to avoid endless recursion. | | 150 | * Var_Subst. This marker is used to avoid endless recursion. |
151 | */ | | 151 | */ |
152 | VFL_IN_USE = 1 << 0, | | 152 | VFL_IN_USE = 1 << 0, |
153 | | | 153 | |
154 | /* | | 154 | /* |
155 | * The variable comes from the environment. | | 155 | * The variable comes from the environment. |
156 | * These variables are not registered in any GNode, therefore they | | 156 | * These variables are not registered in any GNode, therefore they |
| @@ -2496,29 +2496,32 @@ ApplyModifier_Defined(const char **pp, A | | | @@ -2496,29 +2496,32 @@ ApplyModifier_Defined(const char **pp, A |
2496 | if (eflags & VARE_WANTRES) | | 2496 | if (eflags & VARE_WANTRES) |
2497 | Expr_SetValueOwn(expr, Buf_DoneData(&buf)); | | 2497 | Expr_SetValueOwn(expr, Buf_DoneData(&buf)); |
2498 | else | | 2498 | else |
2499 | Buf_Done(&buf); | | 2499 | Buf_Done(&buf); |
2500 | | | 2500 | |
2501 | return AMR_OK; | | 2501 | return AMR_OK; |
2502 | } | | 2502 | } |
2503 | | | 2503 | |
2504 | /* :L */ | | 2504 | /* :L */ |
2505 | static ApplyModifierResult | | 2505 | static ApplyModifierResult |
2506 | ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) | | 2506 | ApplyModifier_Literal(const char **pp, ApplyModifiersState *st) |
2507 | { | | 2507 | { |
2508 | Expr *expr = st->expr; | | 2508 | Expr *expr = st->expr; |
| | | 2509 | |
| | | 2510 | (*pp)++; |
| | | 2511 | |
2509 | Expr_Define(expr); | | 2512 | Expr_Define(expr); |
2510 | Expr_SetValueOwn(expr, bmake_strdup(expr->var->name.str)); | | 2513 | Expr_SetValueOwn(expr, bmake_strdup(expr->var->name.str)); |
2511 | (*pp)++; | | 2514 | |
2512 | return AMR_OK; | | 2515 | return AMR_OK; |
2513 | } | | 2516 | } |
2514 | | | 2517 | |
2515 | static Boolean | | 2518 | static Boolean |
2516 | TryParseTime(const char **pp, time_t *out_time) | | 2519 | TryParseTime(const char **pp, time_t *out_time) |
2517 | { | | 2520 | { |
2518 | char *end; | | 2521 | char *end; |
2519 | unsigned long n; | | 2522 | unsigned long n; |
2520 | | | 2523 | |
2521 | if (!ch_isdigit(**pp)) | | 2524 | if (!ch_isdigit(**pp)) |
2522 | return FALSE; | | 2525 | return FALSE; |
2523 | | | 2526 | |
2524 | errno = 0; | | 2527 | errno = 0; |
| @@ -2543,121 +2546,127 @@ ApplyModifier_Gmtime(const char **pp, Ap | | | @@ -2543,121 +2546,127 @@ ApplyModifier_Gmtime(const char **pp, Ap |
2543 | | | 2546 | |
2544 | if (mod[6] == '=') { | | 2547 | if (mod[6] == '=') { |
2545 | const char *p = mod + 7; | | 2548 | const char *p = mod + 7; |
2546 | if (!TryParseTime(&p, &utc)) { | | 2549 | if (!TryParseTime(&p, &utc)) { |
2547 | Parse_Error(PARSE_FATAL, | | 2550 | Parse_Error(PARSE_FATAL, |
2548 | "Invalid time value: %s", mod + 7); | | 2551 | "Invalid time value: %s", mod + 7); |
2549 | return AMR_CLEANUP; | | 2552 | return AMR_CLEANUP; |
2550 | } | | 2553 | } |
2551 | *pp = p; | | 2554 | *pp = p; |
2552 | } else { | | 2555 | } else { |
2553 | utc = 0; | | 2556 | utc = 0; |
2554 | *pp = mod + 6; | | 2557 | *pp = mod + 6; |
2555 | } | | 2558 | } |
| | | 2559 | |
2556 | Expr_SetValueOwn(st->expr, | | 2560 | Expr_SetValueOwn(st->expr, |
2557 | VarStrftime(st->expr->value.str, TRUE, utc)); | | 2561 | VarStrftime(st->expr->value.str, TRUE, utc)); |
| | | 2562 | |
2558 | return AMR_OK; | | 2563 | return AMR_OK; |
2559 | } | | 2564 | } |
2560 | | | 2565 | |
2561 | /* :localtime */ | | 2566 | /* :localtime */ |
2562 | static ApplyModifierResult | | 2567 | static ApplyModifierResult |
2563 | ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) | | 2568 | ApplyModifier_Localtime(const char **pp, ApplyModifiersState *st) |
2564 | { | | 2569 | { |
2565 | time_t utc; | | 2570 | time_t utc; |
2566 | | | 2571 | |
2567 | const char *mod = *pp; | | 2572 | const char *mod = *pp; |
2568 | if (!ModMatchEq(mod, "localtime", st)) | | 2573 | if (!ModMatchEq(mod, "localtime", st)) |
2569 | return AMR_UNKNOWN; | | 2574 | return AMR_UNKNOWN; |
2570 | | | 2575 | |
2571 | if (mod[9] == '=') { | | 2576 | if (mod[9] == '=') { |
2572 | const char *p = mod + 10; | | 2577 | const char *p = mod + 10; |
2573 | if (!TryParseTime(&p, &utc)) { | | 2578 | if (!TryParseTime(&p, &utc)) { |
2574 | Parse_Error(PARSE_FATAL, | | 2579 | Parse_Error(PARSE_FATAL, |
2575 | "Invalid time value: %s", mod + 10); | | 2580 | "Invalid time value: %s", mod + 10); |
2576 | return AMR_CLEANUP; | | 2581 | return AMR_CLEANUP; |
2577 | } | | 2582 | } |
2578 | *pp = p; | | 2583 | *pp = p; |
2579 | } else { | | 2584 | } else { |
2580 | utc = 0; | | 2585 | utc = 0; |
2581 | *pp = mod + 9; | | 2586 | *pp = mod + 9; |
2582 | } | | 2587 | } |
| | | 2588 | |
2583 | Expr_SetValueOwn(st->expr, | | 2589 | Expr_SetValueOwn(st->expr, |
2584 | VarStrftime(st->expr->value.str, FALSE, utc)); | | 2590 | VarStrftime(st->expr->value.str, FALSE, utc)); |
| | | 2591 | |
2585 | return AMR_OK; | | 2592 | return AMR_OK; |
2586 | } | | 2593 | } |
2587 | | | 2594 | |
2588 | /* :hash */ | | 2595 | /* :hash */ |
2589 | static ApplyModifierResult | | 2596 | static ApplyModifierResult |
2590 | ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) | | 2597 | ApplyModifier_Hash(const char **pp, ApplyModifiersState *st) |
2591 | { | | 2598 | { |
2592 | if (!ModMatch(*pp, "hash", st)) | | 2599 | if (!ModMatch(*pp, "hash", st)) |
2593 | return AMR_UNKNOWN; | | 2600 | return AMR_UNKNOWN; |
| | | 2601 | *pp += 4; |
2594 | | | 2602 | |
2595 | Expr_SetValueOwn(st->expr, VarHash(st->expr->value.str)); | | 2603 | Expr_SetValueOwn(st->expr, VarHash(st->expr->value.str)); |
2596 | *pp += 4; | | 2604 | |
2597 | return AMR_OK; | | 2605 | return AMR_OK; |
2598 | } | | 2606 | } |
2599 | | | 2607 | |
2600 | /* :P */ | | 2608 | /* :P */ |
2601 | static ApplyModifierResult | | 2609 | static ApplyModifierResult |
2602 | ApplyModifier_Path(const char **pp, ApplyModifiersState *st) | | 2610 | ApplyModifier_Path(const char **pp, ApplyModifiersState *st) |
2603 | { | | 2611 | { |
2604 | Expr *expr = st->expr; | | 2612 | Expr *expr = st->expr; |
2605 | GNode *gn; | | 2613 | GNode *gn; |
2606 | char *path; | | 2614 | char *path; |
2607 | | | 2615 | |
| | | 2616 | (*pp)++; |
| | | 2617 | |
2608 | Expr_Define(expr); | | 2618 | Expr_Define(expr); |
2609 | | | 2619 | |
2610 | gn = Targ_FindNode(expr->var->name.str); | | 2620 | gn = Targ_FindNode(expr->var->name.str); |
2611 | if (gn == NULL || gn->type & OP_NOPATH) { | | 2621 | if (gn == NULL || gn->type & OP_NOPATH) { |
2612 | path = NULL; | | 2622 | path = NULL; |
2613 | } else if (gn->path != NULL) { | | 2623 | } else if (gn->path != NULL) { |
2614 | path = bmake_strdup(gn->path); | | 2624 | path = bmake_strdup(gn->path); |
2615 | } else { | | 2625 | } else { |
2616 | SearchPath *searchPath = Suff_FindPath(gn); | | 2626 | SearchPath *searchPath = Suff_FindPath(gn); |
2617 | path = Dir_FindFile(expr->var->name.str, searchPath); | | 2627 | path = Dir_FindFile(expr->var->name.str, searchPath); |
2618 | } | | 2628 | } |
2619 | if (path == NULL) | | 2629 | if (path == NULL) |
2620 | path = bmake_strdup(expr->var->name.str); | | 2630 | path = bmake_strdup(expr->var->name.str); |
2621 | Expr_SetValueOwn(expr, path); | | 2631 | Expr_SetValueOwn(expr, path); |
2622 | | | 2632 | |
2623 | (*pp)++; | | | |
2624 | return AMR_OK; | | 2633 | return AMR_OK; |
2625 | } | | 2634 | } |
2626 | | | 2635 | |
2627 | /* :!cmd! */ | | 2636 | /* :!cmd! */ |
2628 | static ApplyModifierResult | | 2637 | static ApplyModifierResult |
2629 | ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) | | 2638 | ApplyModifier_ShellCommand(const char **pp, ApplyModifiersState *st) |
2630 | { | | 2639 | { |
2631 | Expr *expr = st->expr; | | 2640 | Expr *expr = st->expr; |
2632 | char *cmd; | | 2641 | char *cmd; |
2633 | const char *errfmt; | | 2642 | const char *errfmt; |
2634 | VarParseResult res; | | 2643 | VarParseResult res; |
2635 | | | 2644 | |
2636 | (*pp)++; | | 2645 | (*pp)++; |
2637 | res = ParseModifierPart(pp, '!', expr->eflags, st, &cmd); | | 2646 | res = ParseModifierPart(pp, '!', expr->eflags, st, &cmd); |
2638 | if (res != VPR_OK) | | 2647 | if (res != VPR_OK) |
2639 | return AMR_CLEANUP; | | 2648 | return AMR_CLEANUP; |
2640 | | | 2649 | |
2641 | errfmt = NULL; | | 2650 | errfmt = NULL; |
2642 | if (expr->eflags & VARE_WANTRES) | | 2651 | if (expr->eflags & VARE_WANTRES) |
2643 | Expr_SetValueOwn(expr, Cmd_Exec(cmd, &errfmt)); | | 2652 | Expr_SetValueOwn(expr, Cmd_Exec(cmd, &errfmt)); |
2644 | else | | 2653 | else |
2645 | Expr_SetValueRefer(expr, ""); | | 2654 | Expr_SetValueRefer(expr, ""); |
2646 | if (errfmt != NULL) | | 2655 | if (errfmt != NULL) |
2647 | Error(errfmt, cmd); /* XXX: why still return AMR_OK? */ | | 2656 | Error(errfmt, cmd); /* XXX: why still return AMR_OK? */ |
2648 | free(cmd); | | 2657 | free(cmd); |
2649 | | | | |
2650 | Expr_Define(expr); | | 2658 | Expr_Define(expr); |
| | | 2659 | |
2651 | return AMR_OK; | | 2660 | return AMR_OK; |
2652 | } | | 2661 | } |
2653 | | | 2662 | |
2654 | /* | | 2663 | /* |
2655 | * The :range modifier generates an integer sequence as long as the words. | | 2664 | * The :range modifier generates an integer sequence as long as the words. |
2656 | * The :range=7 modifier generates an integer sequence from 1 to 7. | | 2665 | * The :range=7 modifier generates an integer sequence from 1 to 7. |
2657 | */ | | 2666 | */ |
2658 | static ApplyModifierResult | | 2667 | static ApplyModifierResult |
2659 | ApplyModifier_Range(const char **pp, ApplyModifiersState *st) | | 2668 | ApplyModifier_Range(const char **pp, ApplyModifiersState *st) |
2660 | { | | 2669 | { |
2661 | size_t n; | | 2670 | size_t n; |
2662 | Buffer buf; | | 2671 | Buffer buf; |
2663 | size_t i; | | 2672 | size_t i; |
| @@ -2939,55 +2948,55 @@ static void | | | @@ -2939,55 +2948,55 @@ static void |
2939 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | | 2948 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) |
2940 | { | | 2949 | { |
2941 | SepBuf_AddStr(buf, word); | | 2950 | SepBuf_AddStr(buf, word); |
2942 | } | | 2951 | } |
2943 | | | 2952 | |
2944 | /* :ts<separator> */ | | 2953 | /* :ts<separator> */ |
2945 | static ApplyModifierResult | | 2954 | static ApplyModifierResult |
2946 | ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) | | 2955 | ApplyModifier_ToSep(const char **pp, ApplyModifiersState *st) |
2947 | { | | 2956 | { |
2948 | const char *sep = *pp + 2; | | 2957 | const char *sep = *pp + 2; |
2949 | | | 2958 | |
2950 | /* ":ts<any><endc>" or ":ts<any>:" */ | | 2959 | /* ":ts<any><endc>" or ":ts<any>:" */ |
2951 | if (sep[0] != st->endc && IsDelimiter(sep[1], st)) { | | 2960 | if (sep[0] != st->endc && IsDelimiter(sep[1], st)) { |
2952 | st->sep = sep[0]; | | | |
2953 | *pp = sep + 1; | | 2961 | *pp = sep + 1; |
| | | 2962 | st->sep = sep[0]; |
2954 | goto ok; | | 2963 | goto ok; |
2955 | } | | 2964 | } |
2956 | | | 2965 | |
2957 | /* ":ts<endc>" or ":ts:" */ | | 2966 | /* ":ts<endc>" or ":ts:" */ |
2958 | if (IsDelimiter(sep[0], st)) { | | 2967 | if (IsDelimiter(sep[0], st)) { |
2959 | st->sep = '\0'; /* no separator */ | | | |
2960 | *pp = sep; | | 2968 | *pp = sep; |
| | | 2969 | st->sep = '\0'; /* no separator */ |
2961 | goto ok; | | 2970 | goto ok; |
2962 | } | | 2971 | } |
2963 | | | 2972 | |
2964 | /* ":ts<unrecognised><unrecognised>". */ | | 2973 | /* ":ts<unrecognised><unrecognised>". */ |
2965 | if (sep[0] != '\\') { | | 2974 | if (sep[0] != '\\') { |
2966 | (*pp)++; /* just for backwards compatibility */ | | 2975 | (*pp)++; /* just for backwards compatibility */ |
2967 | return AMR_BAD; | | 2976 | return AMR_BAD; |
2968 | } | | 2977 | } |
2969 | | | 2978 | |
2970 | /* ":ts\n" */ | | 2979 | /* ":ts\n" */ |
2971 | if (sep[1] == 'n') { | | 2980 | if (sep[1] == 'n') { |
2972 | st->sep = '\n'; | | | |
2973 | *pp = sep + 2; | | 2981 | *pp = sep + 2; |
| | | 2982 | st->sep = '\n'; |
2974 | goto ok; | | 2983 | goto ok; |
2975 | } | | 2984 | } |
2976 | | | 2985 | |
2977 | /* ":ts\t" */ | | 2986 | /* ":ts\t" */ |
2978 | if (sep[1] == 't') { | | 2987 | if (sep[1] == 't') { |
2979 | st->sep = '\t'; | | | |
2980 | *pp = sep + 2; | | 2988 | *pp = sep + 2; |
| | | 2989 | st->sep = '\t'; |
2981 | goto ok; | | 2990 | goto ok; |
2982 | } | | 2991 | } |
2983 | | | 2992 | |
2984 | /* ":ts\x40" or ":ts\100" */ | | 2993 | /* ":ts\x40" or ":ts\100" */ |
2985 | { | | 2994 | { |
2986 | const char *p = sep + 1; | | 2995 | const char *p = sep + 1; |
2987 | int base = 8; /* assume octal */ | | 2996 | int base = 8; /* assume octal */ |
2988 | | | 2997 | |
2989 | if (sep[1] == 'x') { | | 2998 | if (sep[1] == 'x') { |
2990 | base = 16; | | 2999 | base = 16; |
2991 | p++; | | 3000 | p++; |
2992 | } else if (!ch_isdigit(sep[1])) { | | 3001 | } else if (!ch_isdigit(sep[1])) { |
2993 | (*pp)++; /* just for backwards compatibility */ | | 3002 | (*pp)++; /* just for backwards compatibility */ |
| @@ -3052,51 +3061,51 @@ ApplyModifier_To(const char **pp, ApplyM | | | @@ -3052,51 +3061,51 @@ ApplyModifier_To(const char **pp, ApplyM |
3052 | *pp = mod + 1; | | 3061 | *pp = mod + 1; |
3053 | return AMR_BAD; /* Found ":t<endc>" or ":t:". */ | | 3062 | return AMR_BAD; /* Found ":t<endc>" or ":t:". */ |
3054 | } | | 3063 | } |
3055 | | | 3064 | |
3056 | if (mod[1] == 's') | | 3065 | if (mod[1] == 's') |
3057 | return ApplyModifier_ToSep(pp, st); | | 3066 | return ApplyModifier_ToSep(pp, st); |
3058 | | | 3067 | |
3059 | if (!IsDelimiter(mod[2], st)) { /* :t<unrecognized> */ | | 3068 | if (!IsDelimiter(mod[2], st)) { /* :t<unrecognized> */ |
3060 | *pp = mod + 1; | | 3069 | *pp = mod + 1; |
3061 | return AMR_BAD; | | 3070 | return AMR_BAD; |
3062 | } | | 3071 | } |
3063 | | | 3072 | |
3064 | if (mod[1] == 'A') { /* :tA */ | | 3073 | if (mod[1] == 'A') { /* :tA */ |
3065 | ModifyWords(st, ModifyWord_Realpath, NULL, st->oneBigWord); | | | |
3066 | *pp = mod + 2; | | 3074 | *pp = mod + 2; |
| | | 3075 | ModifyWords(st, ModifyWord_Realpath, NULL, st->oneBigWord); |
3067 | return AMR_OK; | | 3076 | return AMR_OK; |
3068 | } | | 3077 | } |
3069 | | | 3078 | |
3070 | if (mod[1] == 'u') { /* :tu */ | | 3079 | if (mod[1] == 'u') { /* :tu */ |
3071 | Expr_SetValueOwn(expr, str_toupper(expr->value.str)); | | | |
3072 | *pp = mod + 2; | | 3080 | *pp = mod + 2; |
| | | 3081 | Expr_SetValueOwn(expr, str_toupper(expr->value.str)); |
3073 | return AMR_OK; | | 3082 | return AMR_OK; |
3074 | } | | 3083 | } |
3075 | | | 3084 | |
3076 | if (mod[1] == 'l') { /* :tl */ | | 3085 | if (mod[1] == 'l') { /* :tl */ |
3077 | Expr_SetValueOwn(expr, str_tolower(expr->value.str)); | | | |
3078 | *pp = mod + 2; | | 3086 | *pp = mod + 2; |
| | | 3087 | Expr_SetValueOwn(expr, str_tolower(expr->value.str)); |
3079 | return AMR_OK; | | 3088 | return AMR_OK; |
3080 | } | | 3089 | } |
3081 | | | 3090 | |
3082 | if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ | | 3091 | if (mod[1] == 'W' || mod[1] == 'w') { /* :tW, :tw */ |
3083 | st->oneBigWord = mod[1] == 'W'; | | | |
3084 | *pp = mod + 2; | | 3092 | *pp = mod + 2; |
| | | 3093 | st->oneBigWord = mod[1] == 'W'; |
3085 | return AMR_OK; | | 3094 | return AMR_OK; |
3086 | } | | 3095 | } |
3087 | | | 3096 | |
3088 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ | | 3097 | /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ |
3089 | *pp = mod + 1; | | 3098 | *pp = mod + 1; /* XXX: unnecessary but observable */ |
3090 | return AMR_BAD; | | 3099 | return AMR_BAD; |
3091 | } | | 3100 | } |
3092 | | | 3101 | |
3093 | /* :[#], :[1], :[-1..1], etc. */ | | 3102 | /* :[#], :[1], :[-1..1], etc. */ |
3094 | static ApplyModifierResult | | 3103 | static ApplyModifierResult |
3095 | ApplyModifier_Words(const char **pp, ApplyModifiersState *st) | | 3104 | ApplyModifier_Words(const char **pp, ApplyModifiersState *st) |
3096 | { | | 3105 | { |
3097 | Expr *expr = st->expr; | | 3106 | Expr *expr = st->expr; |
3098 | char *estr; | | 3107 | char *estr; |
3099 | int first, last; | | 3108 | int first, last; |
3100 | VarParseResult res; | | 3109 | VarParseResult res; |
3101 | const char *p; | | 3110 | const char *p; |
3102 | | | 3111 | |
| @@ -3206,26 +3215,28 @@ ShuffleStrings(char **strs, size_t n) | | | @@ -3206,26 +3215,28 @@ ShuffleStrings(char **strs, size_t n) |
3206 | size_t rndidx = (size_t)random() % (i + 1); | | 3215 | size_t rndidx = (size_t)random() % (i + 1); |
3207 | char *t = strs[i]; | | 3216 | char *t = strs[i]; |
3208 | strs[i] = strs[rndidx]; | | 3217 | strs[i] = strs[rndidx]; |
3209 | strs[rndidx] = t; | | 3218 | strs[rndidx] = t; |
3210 | } | | 3219 | } |
3211 | } | | 3220 | } |
3212 | | | 3221 | |
3213 | /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ | | 3222 | /* :O (order ascending) or :Or (order descending) or :Ox (shuffle) */ |
3214 | static ApplyModifierResult | | 3223 | static ApplyModifierResult |
3215 | ApplyModifier_Order(const char **pp, ApplyModifiersState *st) | | 3224 | ApplyModifier_Order(const char **pp, ApplyModifiersState *st) |
3216 | { | | 3225 | { |
3217 | const char *mod = (*pp)++; /* skip past the 'O' in any case */ | | 3226 | const char *mod = (*pp)++; /* skip past the 'O' in any case */ |
3218 | | | 3227 | |
| | | 3228 | /* TODO: separate parsing from evaluating */ |
| | | 3229 | |
3219 | Words words = Str_Words(st->expr->value.str, FALSE); | | 3230 | Words words = Str_Words(st->expr->value.str, FALSE); |
3220 | | | 3231 | |
3221 | if (IsDelimiter(mod[1], st)) { | | 3232 | if (IsDelimiter(mod[1], st)) { |
3222 | /* :O sorts ascending */ | | 3233 | /* :O sorts ascending */ |
3223 | qsort(words.words, words.len, sizeof words.words[0], | | 3234 | qsort(words.words, words.len, sizeof words.words[0], |
3224 | str_cmp_asc); | | 3235 | str_cmp_asc); |
3225 | | | 3236 | |
3226 | } else if ((mod[1] == 'r' || mod[1] == 'x') && | | 3237 | } else if ((mod[1] == 'r' || mod[1] == 'x') && |
3227 | IsDelimiter(mod[2], st)) { | | 3238 | IsDelimiter(mod[2], st)) { |
3228 | (*pp)++; | | 3239 | (*pp)++; |
3229 | | | 3240 | |
3230 | if (mod[1] == 'r') { /* :Or sorts descending */ | | 3241 | if (mod[1] == 'r') { /* :Or sorts descending */ |
3231 | qsort(words.words, words.len, sizeof words.words[0], | | 3242 | qsort(words.words, words.len, sizeof words.words[0], |
| @@ -3311,26 +3322,28 @@ ApplyModifier_IfElse(const char **pp, Ap | | | @@ -3311,26 +3322,28 @@ ApplyModifier_IfElse(const char **pp, Ap |
3311 | * it was not already set. | | 3322 | * it was not already set. |
3312 | * ::+=<str> Appends <str> to variable. | | 3323 | * ::+=<str> Appends <str> to variable. |
3313 | * ::!=<cmd> Assigns output of <cmd> as the new value of | | 3324 | * ::!=<cmd> Assigns output of <cmd> as the new value of |
3314 | * variable. | | 3325 | * variable. |
3315 | */ | | 3326 | */ |
3316 | static ApplyModifierResult | | 3327 | static ApplyModifierResult |
3317 | ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) | | 3328 | ApplyModifier_Assign(const char **pp, ApplyModifiersState *st) |
3318 | { | | 3329 | { |
3319 | Expr *expr = st->expr; | | 3330 | Expr *expr = st->expr; |
3320 | GNode *scope; | | 3331 | GNode *scope; |
3321 | char *val; | | 3332 | char *val; |
3322 | VarParseResult res; | | 3333 | VarParseResult res; |
3323 | | | 3334 | |
| | | 3335 | /* TODO: separate parsing from evaluating */ |
| | | 3336 | |
3324 | const char *mod = *pp; | | 3337 | const char *mod = *pp; |
3325 | const char *op = mod + 1; | | 3338 | const char *op = mod + 1; |
3326 | | | 3339 | |
3327 | if (op[0] == '=') | | 3340 | if (op[0] == '=') |
3328 | goto ok; | | 3341 | goto ok; |
3329 | if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=') | | 3342 | if ((op[0] == '!' || op[0] == '+' || op[0] == '?') && op[1] == '=') |
3330 | goto ok; | | 3343 | goto ok; |
3331 | return AMR_UNKNOWN; /* "::<unrecognised>" */ | | 3344 | return AMR_UNKNOWN; /* "::<unrecognised>" */ |
3332 | | | 3345 | |
3333 | ok: | | 3346 | ok: |
3334 | if (expr->var->name.str[0] == '\0') { | | 3347 | if (expr->var->name.str[0] == '\0') { |
3335 | *pp = mod + 1; | | 3348 | *pp = mod + 1; |
3336 | return AMR_BAD; | | 3349 | return AMR_BAD; |
| @@ -3403,49 +3416,56 @@ ApplyModifier_Remember(const char **pp, | | | @@ -3403,49 +3416,56 @@ ApplyModifier_Remember(const char **pp, |
3403 | Expr *expr = st->expr; | | 3416 | Expr *expr = st->expr; |
3404 | const char *mod = *pp; | | 3417 | const char *mod = *pp; |
3405 | if (!ModMatchEq(mod, "_", st)) | | 3418 | if (!ModMatchEq(mod, "_", st)) |
3406 | return AMR_UNKNOWN; | | 3419 | return AMR_UNKNOWN; |
3407 | | | 3420 | |
3408 | if (mod[1] == '=') { | | 3421 | if (mod[1] == '=') { |
3409 | /* | | 3422 | /* |
3410 | * XXX: This ad-hoc call to strcspn deviates from the usual | | 3423 | * XXX: This ad-hoc call to strcspn deviates from the usual |
3411 | * behavior defined in ParseModifierPart. This creates an | | 3424 | * behavior defined in ParseModifierPart. This creates an |
3412 | * unnecessary, undocumented inconsistency in make. | | 3425 | * unnecessary, undocumented inconsistency in make. |
3413 | */ | | 3426 | */ |
3414 | size_t n = strcspn(mod + 2, ":)}"); | | 3427 | size_t n = strcspn(mod + 2, ":)}"); |
3415 | char *name = bmake_strldup(mod + 2, n); | | 3428 | char *name = bmake_strldup(mod + 2, n); |
| | | 3429 | *pp = mod + 2 + n; |
| | | 3430 | |
| | | 3431 | /* |
| | | 3432 | * FIXME: do not expand the variable name here; it would only |
| | | 3433 | * work for single-character variable names anyway. |
| | | 3434 | */ |
3416 | Var_SetExpand(expr->scope, name, expr->value.str); | | 3435 | Var_SetExpand(expr->scope, name, expr->value.str); |
3417 | free(name); | | 3436 | free(name); |
3418 | *pp = mod + 2 + n; | | | |
3419 | } else { | | 3437 | } else { |
3420 | Var_Set(expr->scope, "_", expr->value.str); | | | |
3421 | *pp = mod + 1; | | 3438 | *pp = mod + 1; |
| | | 3439 | |
| | | 3440 | Var_Set(expr->scope, "_", expr->value.str); |
3422 | } | | 3441 | } |
3423 | return AMR_OK; | | 3442 | return AMR_OK; |
3424 | } | | 3443 | } |
3425 | | | 3444 | |
3426 | /* | | 3445 | /* |
3427 | * Apply the given function to each word of the variable value, | | 3446 | * Apply the given function to each word of the variable value, |
3428 | * for a single-letter modifier such as :H, :T. | | 3447 | * for a single-letter modifier such as :H, :T. |
3429 | */ | | 3448 | */ |
3430 | static ApplyModifierResult | | 3449 | static ApplyModifierResult |
3431 | ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, | | 3450 | ApplyModifier_WordFunc(const char **pp, ApplyModifiersState *st, |
3432 | ModifyWordProc modifyWord) | | 3451 | ModifyWordProc modifyWord) |
3433 | { | | 3452 | { |
3434 | if (!IsDelimiter((*pp)[1], st)) | | 3453 | if (!IsDelimiter((*pp)[1], st)) |
3435 | return AMR_UNKNOWN; | | 3454 | return AMR_UNKNOWN; |
| | | 3455 | (*pp)++; |
3436 | | | 3456 | |
3437 | ModifyWords(st, modifyWord, NULL, st->oneBigWord); | | 3457 | ModifyWords(st, modifyWord, NULL, st->oneBigWord); |
3438 | (*pp)++; | | 3458 | |
3439 | return AMR_OK; | | 3459 | return AMR_OK; |
3440 | } | | 3460 | } |
3441 | | | 3461 | |
3442 | static ApplyModifierResult | | 3462 | static ApplyModifierResult |
3443 | ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) | | 3463 | ApplyModifier_Unique(const char **pp, ApplyModifiersState *st) |
3444 | { | | 3464 | { |
3445 | if (!IsDelimiter((*pp)[1], st)) | | 3465 | if (!IsDelimiter((*pp)[1], st)) |
3446 | return AMR_UNKNOWN; | | 3466 | return AMR_UNKNOWN; |
3447 | (*pp)++; | | 3467 | (*pp)++; |
3448 | | | 3468 | |
3449 | Expr_SetValueOwn(st->expr, VarUniq(st->expr->value.str)); | | 3469 | Expr_SetValueOwn(st->expr, VarUniq(st->expr->value.str)); |
3450 | | | 3470 | |
3451 | return AMR_OK; | | 3471 | return AMR_OK; |
| @@ -3507,44 +3527,45 @@ ApplyModifier_SysV(const char **pp, Appl | | | @@ -3507,44 +3527,45 @@ ApplyModifier_SysV(const char **pp, Appl |
3507 | return AMR_OK; | | 3527 | return AMR_OK; |
3508 | } | | 3528 | } |
3509 | #endif | | 3529 | #endif |
3510 | | | 3530 | |
3511 | #ifdef SUNSHCMD | | 3531 | #ifdef SUNSHCMD |
3512 | /* :sh */ | | 3532 | /* :sh */ |
3513 | static ApplyModifierResult | | 3533 | static ApplyModifierResult |
3514 | ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) | | 3534 | ApplyModifier_SunShell(const char **pp, ApplyModifiersState *st) |
3515 | { | | 3535 | { |
3516 | Expr *expr = st->expr; | | 3536 | Expr *expr = st->expr; |
3517 | const char *p = *pp; | | 3537 | const char *p = *pp; |
3518 | if (!(p[1] == 'h' && IsDelimiter(p[2], st))) | | 3538 | if (!(p[1] == 'h' && IsDelimiter(p[2], st))) |
3519 | return AMR_UNKNOWN; | | 3539 | return AMR_UNKNOWN; |
| | | 3540 | *pp = p + 2; |
3520 | | | 3541 | |
3521 | if (expr->eflags & VARE_WANTRES) { | | 3542 | if (expr->eflags & VARE_WANTRES) { |
3522 | const char *errfmt; | | 3543 | const char *errfmt; |
3523 | char *output = Cmd_Exec(expr->value.str, &errfmt); | | 3544 | char *output = Cmd_Exec(expr->value.str, &errfmt); |
3524 | if (errfmt != NULL) | | 3545 | if (errfmt != NULL) |
3525 | Error(errfmt, expr->value.str); | | 3546 | Error(errfmt, expr->value.str); |
3526 | Expr_SetValueOwn(expr, output); | | 3547 | Expr_SetValueOwn(expr, output); |
3527 | } else { | | 3548 | } else { |
3528 | /* | | 3549 | /* |
3529 | * TODO: Check whether returning ":sh" would be | | 3550 | * TODO: Check whether returning ":sh" would be |
3530 | * more consistent with the other modifiers. | | 3551 | * more consistent with the other modifiers. |
3531 | * | | 3552 | * |
3532 | * TODO: Add a unit test demonstrating that the | | 3553 | * TODO: Add a unit test demonstrating that the |
3533 | * actual value of this expression has any effect. | | 3554 | * actual value of this expression has any effect. |
3534 | */ | | 3555 | */ |
3535 | Expr_SetValueRefer(expr, ""); | | 3556 | Expr_SetValueRefer(expr, ""); |
3536 | } | | 3557 | } |
3537 | *pp = p + 2; | | 3558 | |
3538 | return AMR_OK; | | 3559 | return AMR_OK; |
3539 | } | | 3560 | } |
3540 | #endif | | 3561 | #endif |
3541 | | | 3562 | |
3542 | static void | | 3563 | static void |
3543 | LogBeforeApply(const ApplyModifiersState *st, const char *mod) | | 3564 | LogBeforeApply(const ApplyModifiersState *st, const char *mod) |
3544 | { | | 3565 | { |
3545 | const Expr *expr = st->expr; | | 3566 | const Expr *expr = st->expr; |
3546 | char eflags_str[VarEvalFlags_ToStringSize]; | | 3567 | char eflags_str[VarEvalFlags_ToStringSize]; |
3547 | char vflags_str[VarFlags_ToStringSize]; | | 3568 | char vflags_str[VarFlags_ToStringSize]; |
3548 | Boolean is_single_char = mod[0] != '\0' && IsDelimiter(mod[1], st); | | 3569 | Boolean is_single_char = mod[0] != '\0' && IsDelimiter(mod[1], st); |
3549 | | | 3570 | |
3550 | /* At this point, only the first character of the modifier can | | 3571 | /* At this point, only the first character of the modifier can |