2 msub - Read file(s) and perform substitutions using values of
3 variables defined in makefile.
5 Syntax: msub [-f makefile] [file ...]
7 Multiple -f options may be given.
9 27 Mar 1990 Paul DuBois dubois@primate.wisc.edu
11 27 Mar 1990 V1.0. Created.
22 extern char *calloc ();
28 typedef struct Def Def;
32 char *var; /* variable name */
33 char *val; /* variable value */
34 int simple; /* whether value has been expanded */
35 Def *nextDef; /* next definition in list */
39 char *usage = "Usage: msub [ -f makefile ] file";
40 char *makefile = NULL;
41 Def *defList = NULL; /* list of definitions */
42 int nDefs = 0; /* number of definitions */
56 while (argc > 0 && argv[0][0] == '-')
58 if (strcmp (argv[0], "-f") == 0)
62 if ((f = fopen (makefile = argv[1], "r")) == NULL)
63 panic ("Can't open makefile");
70 panic (usage); /* bad flag */
73 if (makefile == NULL) /* no -f options given */
75 if ((f = fopen ("makefile", "r")) == NULL)
77 if ((f = fopen ("Makefile", "r")) == NULL)
78 panic ("Can't open makefile");
86 /* determine which values need expanding */
87 for (dp = defList; dp != NULL; dp = dp->nextDef)
88 dp->simple = !FindVarRef (dp->val, NULL, NULL, false);
90 /* expand values to eliminate embedded var references */
91 for (pass = 0; pass < nDefs; pass++)
94 for (dp = defList; dp != NULL; dp = dp->nextDef)
99 if (changes == 0) /* loop while values expand */
103 /* sanity check: shouldn't have to make more than nDefs passes */
105 panic ("Too many expansion passes. Something's wrong!");
110 args of form "foo=bar" are taken to be defs to add in
112 while (argc > 0 && strchr(argv[0], '=') && isalpha(argv[0][0]))
114 char name[BUFSIZ], *np, *p;
117 /* copied from below */
119 while (isalnum (*p) || *p == '_')
122 while (isspace (*p)) /* skip whitespace */
124 if (*p++ == '=') /* it's a definition */
126 /* skip leading/trailing whitespace */
130 while (len > 0 && isspace (p[len-1]))
133 /* find var refs in value -- NUKED */
134 /* FindAllVarRefs (p); */
135 /* also NUKED: continue; */
137 /* end of: copied from below */
141 /* end of partain addition */
143 /* read source file(s) and perform substitutions */
146 else while (argc > 0)
148 if ((f = fopen (*argv, "r")) == NULL)
150 fprintf (stderr, "Can't open \"%s\". ", *argv);
170 char input[BUFSIZ * 4], name[BUFSIZ], *p, *np;
173 while (GetLine (f, input)) /* get line, check whether def'n */
175 for (p = input; isspace (*p); p++) { /* nop */ }
176 if (*p == '#' || *p == '\0') /* comment or blank line */
178 if (isalpha (*p)) /* look for var name */
181 while (isalnum (*p) || *p == '_')
184 while (isspace (*p)) /* skip whitespace */
186 if (*p++ == '=') /* it's a definition */
188 /* skip leading/trailing whitespace */
192 while (len > 0 && isspace (p[len-1]))
195 /* find var refs in value */
200 /* not a definition; find var refs anywhere in line */
201 FindAllVarRefs (input);
207 Find definition by variable name.
210 Def *FindDefByVar (s)
215 for (dp = defList; dp != NULL; dp = dp->nextDef)
217 if (strcmp (dp->var, s) == 0)
225 Add a definition. If the name hasn't been seen yet, create a new
226 definition on the list. If the name has been seen, and replace is
227 non-zero, replace the current value with the new one. (replace will
228 be zero if we're just adding a variable which is known by its being
229 referenced somewhere.)
232 AddDef (name, value, replace)
238 if ((dp = FindDefByVar (name)) == NULL)
240 if ((dp = (Def *) calloc (1, sizeof (Def))) == NULL)
241 panic ("AddDef: out of memory");
242 dp->var = NewString (name);
243 dp->val = NewString (value);
244 dp->simple = 0; /* assume not */
245 dp->nextDef = defList;
252 dp->val = NewString (value);
258 Replace instances of '$$' with a single ^A.
266 for (dp = defList; dp != NULL; dp = dp->nextDef)
268 for (p = q = dp->val; *p != '\0'; p++, q++)
271 if (*p == '$' && *(p+1) == '$')
283 Replace instances of ^A with a '$'.
291 for (dp = defList; dp != NULL; dp = dp->nextDef)
293 for (p = dp->val; *p != '\0'; p++)
303 Find variable reference in variable value. begin is set to
304 the index of the '$' and end is set to the index of the closing
305 delimiter. (If either is NULL, it is not set.)
307 recogEsc is non-zero (true) if '$$' is recognized as an escaped '$'
308 and skipped. It will be true during initial searching for var refs
309 and while substituting in source files, false while expanding variable
312 $v, ${}, ${1}, ${v), etc. are not accepted as valid and are ignored.
315 FindVarRef (s, beg, end, recogEsc)
317 int *beg, *end, recogEsc;
325 while ((c = s[i]) != '\0')
329 if ((c = s[i+1]) == '{' || c == '(')
331 if (recogEsc && c == '$') /* escaped $ */
337 return (0); /* no reference */
338 if (beg != (int *) NULL)
345 if (!isalpha (s[i])) /* must have at least one char, must */
346 continue; /* begin with letter */
347 while ((c = s[++i]) != '\0')
349 if (c == delim) /* find matching delim */
351 if (end != (int *) NULL)
355 if (!isalnum (c) && c != '_')
368 while (FindVarRef (s, &begin, &end, true))
370 /* add with empty value if unknown, */
371 /* but don't replace value if known */
372 strncpy (name, s + begin + 2, end - begin - 2);
373 name[end-begin-2] = '\0';
374 AddDef (name, "", 0);
381 Pull out a variable reference, skipping leading '$(' or '${' and
385 YankVarRef (dst, src, begin, end)
389 strncpy (dst, src + begin + 2, end - begin - 2);
390 dst[end - begin - 2] = '\0';
395 Look for variable references in a variable value and expand them
396 when possible. If a variable is referenced but never defined, it
397 disappears. If a variable is referenced, but its value has not itself
398 been fully expanded, defer expansion of value until another pass, at
399 which time the referenced variable might then be expanded. This
400 prevents infinite expansions on circular references.
407 /* partain: made 4 * BUFSIZ
410 char buf[4 * BUFSIZ];
413 while (FindVarRef (dp->val, &begin, &end, false))
415 YankVarRef (buf, dp->val, begin, end);
416 if ((dp2 = FindDefByVar (buf)) == NULL)
418 fprintf (stderr, "Expand error: can't find %s, ", buf);
421 if (!dp2->simple) /* can't expand, give up for now */
423 dp->val[begin] = '\0';
424 sprintf (buf, "%s%s%s", dp->val, dp2->val, &(dp->val)[end+1]);
426 dp->val = NewString (buf);
429 dp->simple = !FindVarRef (dp->val, NULL, NULL, false);
434 Read through file, performing substitutions for any variables
435 known from Makefile. If a variable reference is found that is
436 for an unknown variable, leave it alone, as it may be a reference
437 to a real variable in a shell script.
444 char input[BUFSIZ], var[BUFSIZ], *p;
447 while (fgets (input, sizeof (input), f) != NULL)
450 while (FindVarRef (p, &begin, &end, true))
452 write (1, p, begin); /* write prefix */
453 YankVarRef (var, p, begin, end);
454 /* if var is known from makefile, write */
455 /* value, else just echo the reference */
456 if ((dp = FindDefByVar (var)) != NULL)
457 write (1, dp->val, strlen (dp->val));
459 write (1, p + begin, end - begin + 1);
462 write (1, p, strlen (p));
468 Get next line from Makefile (combines continuation lines into one).
469 No overflow checking, oops.
477 int loop = 1, haveLine = 0, len;
480 while (loop && fgets (buf, sizeof (buf), f) != NULL)
485 if (len > 0 && buf[len-1] == '\n') /* trim newline */
487 if (len > 0 && buf[len-1] == '\\') /* need continuation */
499 Allocate space for a string, copy the string into it, and return
500 a pointer to the copy.
509 if ((p = calloc (1, strlen (s) + 1)) == NULL)
510 panic ("NewString: out of space");
511 return (strcpy (p, s));
518 fprintf (stderr, "%s\n", s);