Module Name: src Committed By: rillig Date: Wed Jul 29 20:57:31 UTC 2020
Modified Files: src/usr.bin/make: Makefile var.c Log Message: make(1): use specialized return type for ApplyModifier functions This makes it immediately obvious what happens after a modifier has been applied, instead of having to translate single-character mnemonics or booleans to their actual intention. This also reduces the size of the binary since there are fewer jumps. To generate a diff of this commit: cvs rdiff -u -r1.75 -r1.76 src/usr.bin/make/Makefile cvs rdiff -u -r1.355 -r1.356 src/usr.bin/make/var.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/Makefile diff -u src/usr.bin/make/Makefile:1.75 src/usr.bin/make/Makefile:1.76 --- src/usr.bin/make/Makefile:1.75 Sun Jul 26 20:04:57 2020 +++ src/usr.bin/make/Makefile Wed Jul 29 20:57:31 2020 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.75 2020/07/26 20:04:57 rillig Exp $ +# $NetBSD: Makefile,v 1.76 2020/07/29 20:57:31 rillig Exp $ # @(#)Makefile 5.2 (Berkeley) 12/28/90 PROG= make @@ -77,3 +77,10 @@ test: .MAKE accept: .MAKE cd ${.CURDIR}/unit-tests && ${.MAKE} ${.TARGET} + +retest: + ${.MAKE} -C ${.CURDIR}/unit-tests cleandir +.if ${USE_COVERAGE} == yes + rm -f *.gcov *.gcda +.endif + ${.MAKE} test Index: src/usr.bin/make/var.c diff -u src/usr.bin/make/var.c:1.355 src/usr.bin/make/var.c:1.356 --- src/usr.bin/make/var.c:1.355 Wed Jul 29 20:33:38 2020 +++ src/usr.bin/make/var.c Wed Jul 29 20:57:31 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $ */ +/* $NetBSD: var.c,v 1.356 2020/07/29 20:57:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $"; +static char rcsid[] = "$NetBSD: var.c,v 1.356 2020/07/29 20:57:31 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: var.c,v 1.355 2020/07/29 20:33:38 rillig Exp $"); +__RCSID("$NetBSD: var.c,v 1.356 2020/07/29 20:57:31 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -2066,6 +2066,14 @@ typedef struct { } ApplyModifiersState; +typedef enum { + AMR_OK, /* Continue parsing */ + AMR_UNKNOWN, /* Not a match, try others as well */ + AMR_BAD, /* Error out with message */ + AMR_CLEANUP /* Error out with "missing delimiter", + * if st->missing_delim is set. */ +} ApplyModifierResult; + /* we now have some modifiers with long names */ static Boolean ModMatch(const char *mod, const char *modname, char endc) @@ -2084,7 +2092,7 @@ ModMatchEq(const char *mod, const char * } /* :@var@...${var}...@ */ -static Boolean +static ApplyModifierResult ApplyModifier_Loop(const char *mod, ApplyModifiersState *st) { ModifyWord_LoopArgs args; @@ -2095,14 +2103,14 @@ ApplyModifier_Loop(const char *mod, Appl st->ctxt, NULL, NULL, NULL); if (args.tvar == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } args.str = ParseModifierPart(&st->next, delim, st->eflags & ~VARE_WANTRES, st->ctxt, NULL, NULL, NULL); if (args.str == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } args.eflags = st->eflags & (VARE_UNDEFERR | VARE_WANTRES); @@ -2114,11 +2122,11 @@ ApplyModifier_Loop(const char *mod, Appl Var_Delete(args.tvar, st->ctxt); free(args.tvar); free(args.str); - return TRUE; + return AMR_OK; } /* :Ddefined or :Uundefined */ -static void +static ApplyModifierResult ApplyModifier_Defined(const char *mod, ApplyModifiersState *st) { Buffer buf; /* Buffer for patterns */ @@ -2179,15 +2187,16 @@ ApplyModifier_Defined(const char *mod, A st->newVal = st->val; Buf_Destroy(&buf, TRUE); } + return AMR_OK; } /* :gmtime */ -static Boolean +static ApplyModifierResult ApplyModifier_Gmtime(const char *mod, ApplyModifiersState *st) { if (!ModMatchEq(mod, "gmtime", st->endc)) { st->next = mod + 1; - return FALSE; + return AMR_UNKNOWN; } time_t utc; @@ -2200,7 +2209,7 @@ ApplyModifier_Gmtime(const char *mod, Ap st->next = mod + 6; } st->newVal = VarStrftime(st->val, 1, utc); - return TRUE; + return AMR_OK; } /* :localtime */ @@ -2209,7 +2218,7 @@ ApplyModifier_Localtime(const char *mod, { if (!ModMatchEq(mod, "localtime", st->endc)) { st->next = mod + 1; - return FALSE; + return AMR_UNKNOWN; } time_t utc; @@ -2222,25 +2231,25 @@ ApplyModifier_Localtime(const char *mod, st->next = mod + 9; } st->newVal = VarStrftime(st->val, 0, utc); - return TRUE; + return AMR_OK; } /* :hash */ -static Boolean +static ApplyModifierResult ApplyModifier_Hash(const char *mod, ApplyModifiersState *st) { if (!ModMatch(mod, "hash", st->endc)) { st->next = mod + 1; - return FALSE; + return AMR_UNKNOWN; } st->newVal = VarHash(st->val); st->next = mod + 4; - return TRUE; + return AMR_OK; } /* :P */ -static void +static ApplyModifierResult ApplyModifier_Path(const char *mod, ApplyModifiersState *st) { if (st->v->flags & VAR_JUNK) @@ -2256,10 +2265,11 @@ ApplyModifier_Path(const char *mod, Appl if (!st->newVal) st->newVal = bmake_strdup(st->v->name); st->next = mod + 1; + return AMR_OK; } /* :!cmd! */ -static Boolean +static ApplyModifierResult ApplyModifier_Exclam(const char *mod, ApplyModifiersState *st) { st->next = mod + 1; @@ -2268,7 +2278,7 @@ ApplyModifier_Exclam(const char *mod, Ap NULL, NULL, NULL); if (cmd == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } const char *emsg = NULL; @@ -2279,20 +2289,20 @@ ApplyModifier_Exclam(const char *mod, Ap free(cmd); if (emsg) - Error(emsg, st->val); + Error(emsg, st->val); /* XXX: why still return AMR_OK? */ if (st->v->flags & VAR_JUNK) st->v->flags |= VAR_KEEP; - return TRUE; + return AMR_OK; } /* :range */ -static Boolean +static ApplyModifierResult ApplyModifier_Range(const char *mod, ApplyModifiersState *st) { if (!ModMatchEq(mod, "range", st->endc)) { st->next = mod + 1; - return FALSE; + return AMR_UNKNOWN; } int n; @@ -2305,11 +2315,11 @@ ApplyModifier_Range(const char *mod, App st->next = mod + 5; } st->newVal = VarRange(st->val, n); - return TRUE; + return AMR_OK; } /* :Mpattern or :Npattern */ -static void +static ApplyModifierResult ApplyModifier_Match(const char *mod, ApplyModifiersState *st) { Boolean copy = FALSE; /* pattern should be, or has been, copied */ @@ -2381,10 +2391,11 @@ ApplyModifier_Match(const char *mod, App st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, callback, pattern); free(pattern); + return AMR_OK; } /* :S,from,to, */ -static Boolean +static ApplyModifierResult ApplyModifier_Subst(const char * const mod, ApplyModifiersState *st) { ModifyWord_SubstArgs args; @@ -2407,7 +2418,7 @@ ApplyModifier_Subst(const char * const m &args.lhsLen, &args.pflags, NULL); if (lhs == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } args.lhs = lhs; @@ -2415,7 +2426,7 @@ ApplyModifier_Subst(const char * const m &args.rhsLen, NULL, &args); if (rhs == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } args.rhs = rhs; @@ -2444,13 +2455,13 @@ ApplyModifier_Subst(const char * const m free(lhs); free(rhs); - return TRUE; + return AMR_OK; } #ifndef NO_REGEX /* :C,from,to, */ -static Boolean +static ApplyModifierResult ApplyModifier_Regex(const char *mod, ApplyModifiersState *st) { ModifyWord_SubstRegexArgs args; @@ -2465,7 +2476,7 @@ ApplyModifier_Regex(const char *mod, App NULL, NULL, NULL); if (re == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } args.replace = ParseModifierPart(&st->next, delim, st->eflags, st->ctxt, @@ -2473,7 +2484,7 @@ ApplyModifier_Regex(const char *mod, App if (args.replace == NULL) { free(re); st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } for (;; st->next++) { @@ -2496,7 +2507,7 @@ ApplyModifier_Regex(const char *mod, App if (error) { VarREError(error, &args.re, "RE substitution error"); free(args.replace); - return FALSE; + return AMR_CLEANUP; } args.nsub = args.re.re_nsub + 1; @@ -2508,7 +2519,7 @@ ApplyModifier_Regex(const char *mod, App ModifyWord_SubstRegex, &args); regfree(&args.re); free(args.replace); - return TRUE; + return AMR_OK; } #endif @@ -2519,7 +2530,7 @@ ModifyWord_Copy(const char *word, SepBuf } /* :ts<separator> */ -static Boolean +static ApplyModifierResult ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) { if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { @@ -2552,38 +2563,38 @@ ApplyModifier_ToSep(const char *sep, App goto get_numeric; default: if (!isdigit((unsigned char)sep[1])) - return FALSE; /* ":ts<backslash><unrecognised>". */ + return AMR_BAD; /* ":ts<backslash><unrecognised>". */ char *end; get_numeric: st->sep = strtoul(sep + 1 + (sep[1] == 'x'), &end, base); if (*end != ':' && *end != st->endc) - return FALSE; + return AMR_BAD; st->next = end; break; } } else { - return FALSE; /* Found ":ts<unrecognised><unrecognised>". */ + return AMR_BAD; /* Found ":ts<unrecognised><unrecognised>". */ } st->newVal = ModifyWords(st->ctxt, st->sep, st->oneBigWord, st->val, ModifyWord_Copy, NULL); - return TRUE; + return AMR_OK; } /* :tA, :tu, :tl, :ts<separator>, etc. */ -static Boolean +static ApplyModifierResult ApplyModifier_To(const char *mod, ApplyModifiersState *st) { st->next = mod + 1; /* make sure it is set */ if (mod[1] == st->endc || mod[1] == ':') - return FALSE; /* Found ":t<endc>" or ":t:". */ + return AMR_BAD; /* Found ":t<endc>" or ":t:". */ if (mod[1] == 's') return ApplyModifier_ToSep(mod + 2, st); if (mod[2] != st->endc && mod[2] != ':') - return FALSE; /* Found ":t<unrecognised><unrecognised>". */ + return AMR_BAD; /* Found ":t<unrecognised><unrecognised>". */ /* Check for two-character options: ":tu", ":tl" */ if (mod[1] == 'A') { /* absolute path */ @@ -2606,13 +2617,13 @@ ApplyModifier_To(const char *mod, ApplyM st->next = mod + 2; } else { /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */ - return FALSE; + return AMR_BAD; } - return TRUE; + return AMR_OK; } /* :[#], :[1], etc. */ -static int +static ApplyModifierResult ApplyModifier_Words(const char *mod, ApplyModifiersState *st) { st->next = mod + 1; /* point to char after '[' */ @@ -2621,7 +2632,7 @@ ApplyModifier_Words(const char *mod, App NULL, NULL, NULL); if (estr == NULL) { st->missing_delim = delim; - return 'c'; + return AMR_CLEANUP; } /* now st->next points just after the closing ']' */ @@ -2706,15 +2717,15 @@ ApplyModifier_Words(const char *mod, App ok: free(estr); - return 0; + return AMR_OK; bad_modifier: free(estr); - return 'b'; + return AMR_BAD; } /* :O or :Ox */ -static Boolean +static ApplyModifierResult ApplyModifier_Order(const char *mod, ApplyModifiersState *st) { char otype; @@ -2727,14 +2738,14 @@ ApplyModifier_Order(const char *mod, App otype = mod[1]; st->next = mod + 2; } else { - return FALSE; + return AMR_BAD; } st->newVal = VarOrder(st->val, otype); - return TRUE; + return AMR_OK; } /* :? then : else */ -static Boolean +static ApplyModifierResult ApplyModifier_IfElse(const char *mod, ApplyModifiersState *st) { Boolean value = FALSE; @@ -2756,7 +2767,7 @@ ApplyModifier_IfElse(const char *mod, Ap NULL, NULL, NULL); if (then_expr == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } delim = st->endc; /* BRCLOSE or PRCLOSE */ @@ -2764,14 +2775,14 @@ ApplyModifier_IfElse(const char *mod, Ap NULL, NULL, NULL); if (else_expr == NULL) { st->missing_delim = delim; - return FALSE; + return AMR_CLEANUP; } st->next--; if (cond_rc == COND_INVALID) { Error("Bad conditional expression `%s' in %s?%s:%s", st->v->name, st->v->name, then_expr, else_expr); - return FALSE; + return AMR_CLEANUP; } if (value) { @@ -2783,7 +2794,7 @@ ApplyModifier_IfElse(const char *mod, Ap } if (st->v->flags & VAR_JUNK) st->v->flags |= VAR_KEEP; - return TRUE; + return AMR_OK; } /* @@ -2807,20 +2818,20 @@ ApplyModifier_IfElse(const char *mod, Ap * ::!=<cmd> Assigns output of <cmd> as the new value of * variable. */ -static int +static ApplyModifierResult ApplyModifier_Assign(const char *mod, ApplyModifiersState *st) { const char *op = mod + 1; if (!(op[0] == '=' || (op[1] == '=' && (op[0] == '!' || op[0] == '+' || op[0] == '?')))) - return 'd'; /* "::<unrecognised>" */ + return AMR_UNKNOWN; /* "::<unrecognised>" */ GNode *v_ctxt; /* context where v belongs */ if (st->v->name[0] == 0) { st->next = mod + 1; - return 'b'; + return AMR_BAD; } v_ctxt = st->ctxt; @@ -2860,7 +2871,7 @@ ApplyModifier_Assign(const char *mod, Ap } if (val == NULL) { st->missing_delim = delim; - return 'c'; + return AMR_CLEANUP; } st->next--; @@ -2891,16 +2902,16 @@ ApplyModifier_Assign(const char *mod, Ap } free(val); st->newVal = varNoError; - return 0; + return AMR_OK; } /* remember current value */ -static Boolean +static ApplyModifierResult ApplyModifier_Remember(const char *mod, ApplyModifiersState *st) { if (!ModMatchEq(mod, "_", st->endc)) { st->next = mod + 1; - return FALSE; + return AMR_UNKNOWN; } if (mod[1] == '=') { @@ -2914,12 +2925,12 @@ ApplyModifier_Remember(const char *mod, st->next = mod + 1; } st->newVal = st->val; - return TRUE; + return AMR_OK; } #ifdef SYSVVARSUB /* :from=to */ -static int +static ApplyModifierResult ApplyModifier_SysV(const char *mod, ApplyModifiersState *st) { Boolean eqFound = FALSE; @@ -2943,7 +2954,7 @@ ApplyModifier_SysV(const char *mod, Appl st->next++; } if (*st->next != st->endc || !eqFound) - return 0; + return AMR_UNKNOWN; char delim = '='; st->next = mod; @@ -2951,7 +2962,7 @@ ApplyModifier_SysV(const char *mod, Appl NULL, NULL, NULL); if (lhs == NULL) { st->missing_delim = delim; - return 'c'; + return AMR_CLEANUP; } delim = st->endc; @@ -2959,7 +2970,7 @@ ApplyModifier_SysV(const char *mod, Appl NULL, NULL, NULL); if (rhs == NULL) { st->missing_delim = delim; - return 'c'; + return AMR_CLEANUP; } /* @@ -2976,7 +2987,7 @@ ApplyModifier_SysV(const char *mod, Appl } free(lhs); free(rhs); - return '='; + return AMR_OK; } #endif @@ -3117,89 +3128,65 @@ ApplyModifiers(char *val, const char * c fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name, *p, st.val); } - st.newVal = var_Error; + st.newVal = var_Error; /* default value, in case of errors */ + st.next = NULL; /* fail fast if an ApplyModifier forgets to set this */ + ApplyModifierResult res = 0; char modifier = *p; - st.next = NULL; /* fail fast if an ApplyModifier forgets to set this */ switch (modifier) { case ':': - { - int res = ApplyModifier_Assign(p, &st); - if (res == 'b') - goto bad_modifier; - if (res == 'c') - goto cleanup; - if (res == 'd') - goto default_case; - break; - } + res = ApplyModifier_Assign(p, &st); + break; case '@': - if (!ApplyModifier_Loop(p, &st)) - goto cleanup; + res = ApplyModifier_Loop(p, &st); break; case '_': - if (!ApplyModifier_Remember(p, &st)) - goto default_case; + res = ApplyModifier_Remember(p, &st); break; case 'D': case 'U': - ApplyModifier_Defined(p, &st); + res = ApplyModifier_Defined(p, &st); break; case 'L': - { - if (st.v->flags & VAR_JUNK) - st.v->flags |= VAR_KEEP; - st.newVal = bmake_strdup(st.v->name); - st.next = p + 1; - break; - } + if (st.v->flags & VAR_JUNK) + st.v->flags |= VAR_KEEP; + st.newVal = bmake_strdup(st.v->name); + st.next = p + 1; + res = AMR_OK; + break; case 'P': - ApplyModifier_Path(p, &st); + res = ApplyModifier_Path(p, &st); break; case '!': - if (!ApplyModifier_Exclam(p, &st)) - goto cleanup; + res = ApplyModifier_Exclam(p, &st); break; case '[': - { - int res = ApplyModifier_Words(p, &st); - if (res == 'b') - goto bad_modifier; - if (res == 'c') - goto cleanup; - break; - } + res = ApplyModifier_Words(p, &st); + break; case 'g': - if (!ApplyModifier_Gmtime(p, &st)) - goto default_case; + res = ApplyModifier_Gmtime(p, &st); break; case 'h': - if (!ApplyModifier_Hash(p, &st)) - goto default_case; + res = ApplyModifier_Hash(p, &st); break; case 'l': - if (!ApplyModifier_Localtime(p, &st)) - goto default_case; + res = ApplyModifier_Localtime(p, &st); break; case 't': - if (!ApplyModifier_To(p, &st)) - goto bad_modifier; + res = ApplyModifier_To(p, &st); break; case 'N': case 'M': - ApplyModifier_Match(p, &st); + res = ApplyModifier_Match(p, &st); break; case 'S': - if (!ApplyModifier_Subst(p, &st)) - goto cleanup; + res = ApplyModifier_Subst(p, &st); break; case '?': - if (!ApplyModifier_IfElse(p, &st)) - goto cleanup; + res = ApplyModifier_IfElse(p, &st); break; #ifndef NO_REGEX case 'C': - if (!ApplyModifier_Regex(p, &st)) - goto cleanup; + res = ApplyModifier_Regex(p, &st); break; #endif case 'q': @@ -3207,56 +3194,60 @@ ApplyModifiers(char *val, const char * c if (p[1] == st.endc || p[1] == ':') { st.newVal = VarQuote(st.val, modifier == 'q'); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; case 'T': if (p[1] == st.endc || p[1] == ':') { st.newVal = ModifyWords(st.ctxt, st.sep, st.oneBigWord, st.val, ModifyWord_Tail, NULL); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; case 'H': if (p[1] == st.endc || p[1] == ':') { st.newVal = ModifyWords(st.ctxt, st.sep, st.oneBigWord, st.val, ModifyWord_Head, NULL); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; case 'E': if (p[1] == st.endc || p[1] == ':') { st.newVal = ModifyWords(st.ctxt, st.sep, st.oneBigWord, st.val, ModifyWord_Suffix, NULL); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; case 'R': if (p[1] == st.endc || p[1] == ':') { st.newVal = ModifyWords(st.ctxt, st.sep, st.oneBigWord, st.val, ModifyWord_Root, NULL); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; case 'r': - if (!ApplyModifier_Range(p, &st)) - goto default_case; + res = ApplyModifier_Range(p, &st); break; case 'O': - if (!ApplyModifier_Order(p, &st)) - goto bad_modifier; + res = ApplyModifier_Order(p, &st); break; case 'u': if (p[1] == st.endc || p[1] == ':') { st.newVal = VarUniq(st.val); st.next = p + 1; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; #ifdef SUNSHCMD case 's': if (p[1] == 'h' && (p[2] == st.endc || p[2] == ':')) { @@ -3268,30 +3259,32 @@ ApplyModifiers(char *val, const char * c } else st.newVal = varNoError; st.next = p + 2; - break; - } - goto default_case; + res = AMR_OK; + } else + res = AMR_UNKNOWN; + break; #endif default: - default_case: - { + res = AMR_UNKNOWN; + } + #ifdef SYSVVARSUB - int res = ApplyModifier_SysV(p, &st); - if (res == 'c') - goto cleanup; - if (res != '=') + if (res == AMR_UNKNOWN) + res = ApplyModifier_SysV(p, &st); #endif - { - Error("Unknown modifier '%c'", *p); - for (st.next = p + 1; - *st.next != ':' && *st.next != st.endc && - *st.next != '\0'; - st.next++) - continue; - st.newVal = var_Error; - } - } - } + + if (res == AMR_UNKNOWN) { + Error("Unknown modifier '%c'", *p); + st.next = p + 1; + while (*st.next != ':' && *st.next != st.endc && *st.next != '\0') + st.next++; + st.newVal = var_Error; + } + if (res == AMR_CLEANUP) + goto cleanup; + if (res == AMR_BAD) + goto bad_modifier; + if (DEBUG(VAR)) { fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", st.v->name, modifier, st.newVal);