Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make(1): refactor ApplyModifiers



details:   https://anonhg.NetBSD.org/src/rev/a07cd121ec5e
branches:  trunk
changeset: 935466:a07cd121ec5e
user:      rillig <rillig%NetBSD.org@localhost>
date:      Fri Jul 03 14:14:04 2020 +0000

description:
make(1): refactor ApplyModifiers

Previously, ApplyModifiers was 1200 lines long and pretty complicated.
Now each of the complicated modifiers has its own function, which reduces
the indentation and makes it possible to use early returns.

diffstat:

 usr.bin/make/var.c |  2211 +++++++++++++++++++++++++++------------------------
 1 files changed, 1167 insertions(+), 1044 deletions(-)

diffs (truncated from 2385 to 300 lines):

diff -r 93cd0892767d -r a07cd121ec5e usr.bin/make/var.c
--- a/usr.bin/make/var.c        Fri Jul 03 14:08:53 2020 +0000
+++ b/usr.bin/make/var.c        Fri Jul 03 14:14:04 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: var.c,v 1.235 2020/07/03 08:13:23 rillig Exp $ */
+/*     $NetBSD: var.c,v 1.236 2020/07/03 14:14:04 rillig Exp $ */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.235 2020/07/03 08:13:23 rillig Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.236 2020/07/03 14:14:04 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.235 2020/07/03 08:13:23 rillig Exp $");
+__RCSID("$NetBSD: var.c,v 1.236 2020/07/03 14:14:04 rillig Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -2467,6 +2467,1023 @@
     return bmake_strdup(buf);
 }
 
+typedef struct {
+    /* const parameters */
+    int startc;
+    int endc;
+    Var * v;
+    GNode *ctxt;
+    int flags;
+    int* lengthPtr;
+    void ** freePtr;
+
+    /* read-write */
+    char *nstr;
+    const char *tstr;
+    const char *start;
+    const char *cp;            /* Secondary pointer into str (place marker
+                                * for tstr) */
+    char termc;                        /* Character which terminated scan */
+    int cnt;                   /* Used to count brace pairs when variable in
+                                * in parens or braces */
+    char delim;
+    int modifier;              /* that we are processing */
+    Var_Parse_State parsestate; /* Flags passed to helper functions */
+
+    /* result */
+    char *newStr;              /* New value to return */
+
+} ApplyModifiersState;
+
+/* we now have some modifiers with long names */
+#define STRMOD_MATCH(s, want, n) \
+    (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
+#define STRMOD_MATCHX(s, want, n) \
+    (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':' || s[n] == '='))
+#define CHARMOD_MATCH(c) (c == st->endc || c == ':')
+
+/* :@var@...${var}...@ */
+static Boolean
+ApplyModifier_At(ApplyModifiersState *st) {
+    VarLoop_t loop;
+    VarPattern_Flags vflags = VAR_NOSUBST;
+
+    st->cp = ++(st->tstr);
+    st->delim = '@';
+    loop.tvar = VarGetPattern(
+       st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
+       &vflags, &loop.tvarLen, NULL);
+    if (loop.tvar == NULL)
+       return FALSE;
+
+    loop.str = VarGetPattern(
+       st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
+       &vflags, &loop.strLen, NULL);
+    if (loop.str == NULL)
+       return FALSE;
+
+    st->termc = *st->cp;
+    st->delim = '\0';
+
+    loop.flags = st->flags & (VARF_UNDEFERR | VARF_WANTRES);
+    loop.ctxt = st->ctxt;
+    st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop);
+    Var_Delete(loop.tvar, st->ctxt);
+    free(loop.tvar);
+    free(loop.str);
+    return TRUE;
+}
+
+/* :Ddefined or :Uundefined */
+static void
+ApplyModifier_Defined(ApplyModifiersState *st)
+{
+    Buffer  buf;       /* Buffer for patterns */
+    int nflags;
+
+    if (st->flags & VARF_WANTRES) {
+       int wantres;
+       if (*st->tstr == 'U')
+           wantres = ((st->v->flags & VAR_JUNK) != 0);
+       else
+           wantres = ((st->v->flags & VAR_JUNK) == 0);
+       nflags = st->flags & ~VARF_WANTRES;
+       if (wantres)
+           nflags |= VARF_WANTRES;
+    } else
+       nflags = st->flags;
+
+    /*
+     * Pass through tstr looking for 1) escaped delimiters,
+     * '$'s and backslashes (place the escaped character in
+     * uninterpreted) and 2) unescaped $'s that aren't before
+     * the delimiter (expand the variable substitution).
+     * The result is left in the Buffer buf.
+     */
+    Buf_Init(&buf, 0);
+    for (st->cp = st->tstr + 1;
+        *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
+        st->cp++) {
+       if (*st->cp == '\\' &&
+           (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
+            st->cp[1] == '\\')) {
+           Buf_AddByte(&buf, st->cp[1]);
+           st->cp++;
+       } else if (*st->cp == '$') {
+           /*
+            * If unescaped dollar sign, assume it's a
+            * variable substitution and recurse.
+            */
+           char    *cp2;
+           int     len;
+           void    *freeIt;
+
+           cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt);
+           Buf_AddBytes(&buf, strlen(cp2), cp2);
+           free(freeIt);
+           st->cp += len - 1;
+       } else {
+           Buf_AddByte(&buf, *st->cp);
+       }
+    }
+
+    st->termc = *st->cp;
+
+    if ((st->v->flags & VAR_JUNK) != 0)
+       st->v->flags |= VAR_KEEP;
+    if (nflags & VARF_WANTRES) {
+       st->newStr = Buf_Destroy(&buf, FALSE);
+    } else {
+       st->newStr = st->nstr;
+       Buf_Destroy(&buf, TRUE);
+    }
+}
+
+/* :gmtime */
+static Boolean
+ApplyModifier_Gmtime(ApplyModifiersState *st)
+{
+    time_t utc;
+    char *ep;
+
+    st->cp = st->tstr + 1;     /* make sure it is set */
+    if (!STRMOD_MATCHX(st->tstr, "gmtime", 6))
+       return FALSE;
+    if (st->tstr[6] == '=') {
+       utc = strtoul(&st->tstr[7], &ep, 10);
+       st->cp = ep;
+    } else {
+       utc = 0;
+       st->cp = st->tstr + 6;
+    }
+    st->newStr = VarStrftime(st->nstr, 1, utc);
+    st->termc = *st->cp;
+    return TRUE;
+}
+
+/* :localtime */
+static Boolean
+ApplyModifier_Localtime(ApplyModifiersState *st)
+{
+    time_t utc;
+    char *ep;
+
+    st->cp = st->tstr + 1;     /* make sure it is set */
+    if (!STRMOD_MATCHX(st->tstr, "localtime", 9))
+       return FALSE;
+
+    if (st->tstr[9] == '=') {
+       utc = strtoul(&st->tstr[10], &ep, 10);
+       st->cp = ep;
+    } else {
+       utc = 0;
+       st->cp = st->tstr + 9;
+    }
+    st->newStr = VarStrftime(st->nstr, 0, utc);
+    st->termc = *st->cp;
+    return TRUE;
+}
+
+/* :hash */
+static Boolean
+ApplyModifier_Hash(ApplyModifiersState *st)
+{
+    st->cp = st->tstr + 1;     /* make sure it is set */
+    if (!STRMOD_MATCH(st->tstr, "hash", 4))
+       return FALSE;
+    st->newStr = VarHash(st->nstr);
+    st->cp = st->tstr + 4;
+    st->termc = *st->cp;
+    return TRUE;
+}
+
+/* :P */
+static void
+ApplyModifier_Path(ApplyModifiersState *st)
+{
+    GNode *gn;
+
+    if ((st->v->flags & VAR_JUNK) != 0)
+       st->v->flags |= VAR_KEEP;
+    gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
+    if (gn == NULL || gn->type & OP_NOPATH) {
+       st->newStr = NULL;
+    } else if (gn->path) {
+       st->newStr = bmake_strdup(gn->path);
+    } else {
+       st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
+    }
+    if (!st->newStr)
+       st->newStr = bmake_strdup(st->v->name);
+    st->cp = ++st->tstr;
+    st->termc = *st->tstr;
+}
+
+/* :!cmd! */
+static Boolean
+ApplyModifier_Exclam(ApplyModifiersState *st)
+{
+    const char *emsg;
+    VarPattern pattern;
+
+    pattern.flags = 0;
+
+    st->delim = '!';
+    emsg = NULL;
+    st->cp = ++st->tstr;
+    pattern.rhs = VarGetPattern(
+       st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
+       NULL, &pattern.rightLen, NULL);
+    if (pattern.rhs == NULL)
+       return FALSE;
+    if (st->flags & VARF_WANTRES)
+       st->newStr = Cmd_Exec(pattern.rhs, &emsg);
+    else
+       st->newStr = varNoError;
+    free(UNCONST(pattern.rhs));
+    if (emsg)
+       Error(emsg, st->nstr);
+    st->termc = *st->cp;
+    st->delim = '\0';
+    if (st->v->flags & VAR_JUNK)
+       st->v->flags |= VAR_KEEP;
+    return TRUE;
+}
+
+/* :range */
+static Boolean
+ApplyModifier_Range(ApplyModifiersState *st)
+{
+    int n;
+    char *ep;
+
+    st->cp = st->tstr + 1;     /* make sure it is set */
+    if (!STRMOD_MATCHX(st->tstr, "range", 5))
+       return FALSE;
+
+    if (st->tstr[5] == '=') {
+       n = strtoul(&st->tstr[6], &ep, 10);
+       st->cp = ep;
+    } else {
+       n = 0;
+       st->cp = st->tstr + 5;
+    }
+    st->newStr = VarRange(st->nstr, n);
+    st->termc = *st->cp;
+    return TRUE;
+}
+
+/* :Mpattern or :Npattern */
+static void
+ApplyModifier_Match(ApplyModifiersState *st)
+{



Home | Main Index | Thread Index | Old Index