/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1990-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* mamake -- MAM make
*
* coded for portability
*/
#if _PACKAGE_ast
#include <ast.h>
#include <error.h>
static const char usage[] =
"[-?\n@(#)$Id: mamake (AT&T Research) 2011-08-31 $\n]"
"[+NAME?mamake - make abstract machine make]"
"[+DESCRIPTION?\bmamake\b reads \amake abstract machine\a target and"
" prerequisite file descriptions from a mamfile (see \b-f\b) and executes"
" actions to update targets that are older than their prerequisites."
" Mamfiles are generated by the \b--mam\b option of \bnmake\b(1) and"
" \bgmake\b(1) and are portable to environments that only have"
" \bsh\b(1) and \bcc\b(1).]"
"[+?In practice \bmamake\b is used to bootstrap build \bnmake\b(1) and"
" \bksh\b(1) in new environments. Mamfiles are used rather than"
" old-\bmake\b makefiles because some features are not reliably supported"
" across all \bmake\b variants:]{"
" [+action execution?Multi-line actions are executed as a"
" unit by \b$SHELL\b. There are some shell constructs"
" that cannot be expressed in an old-\bmake\b makefile.]"
" [+viewpathing?\bVPATH\b is properly interpreted. This allows"
" source to be separate from generated files.]"
" [+recursion?Ordered subdirectory recursion over unrelated"
" makefiles.]"
" }"
"[+?\bmamprobe\b(1) is called to probe and generate system specific variable"
" definitions. The probe information is regenerated when it is older"
" than the \bmamprobe\b command.]"
"[+?For compatibility with \bnmake\b(1) the \b-K\b option and the"
" \brecurse\b and \bcc-*\b command line targets are ignored.]"
"[e:?Explain reason for triggering action. Ignored if -F is on.]"
"[f:?Read \afile\a instead of the default.]:[file:=Mamfile]"
"[i:?Ignore action errors.]"
"[k:?Continue after error with sibling prerequisites.]"
"[n:?Print actions but do not execute. Recursion actions (see \b-r\b) are still"
" executed. Use \b-N\b to disable recursion actions too.]"
"[r:?Recursively make leaf directories matching \apattern\a. Only leaf"
" directories containing a makefile named \bNmakefile\b, \bnmakefile\b,"
" \bMakefile\b or \bmakefile\b are considered. The first makefile"
" found in each leaf directory is scanned for leaf directory"
" prerequisites; the recusion order is determined by a topological sort"
" of these prerequisites.]:[pattern]"
"[C:?Do all work in \adirectory\a. All messages will mention"
" \adirectory\a.]:[directory]"
"[D:?Set the debug trace level to \alevel\a. Higher levels produce more"
" output.]#[level]"
"[F:?Force all targets to be out of date.]"
"[K:?Ignored.]"
"[N:?Like \b-n\b but recursion actions (see \b-r\b) are also disabled.]"
"[V:?Print the program version and exit.]"
"[G:debug-symbols?Compile and link with debugging symbol options enabled.]"
"[S:strip-symbols?Strip link-time static symbols from executables.]"
"\n"
"\n[ target ... ] [ name=value ... ]\n"
"\n"
"[+SEE ALSO?\bgmake\b(1), \bmake\b(1), \bmamprobe\b(1),"
" \bnmake\b(1), \bsh\b(1)]"
;
#else
#define elementsof(x) (sizeof(x)/sizeof(x[0]))
#define newof(p,t,n,x) ((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x)))
#define NiL ((char*)0)
#endif
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#if !_PACKAGE_ast && defined(__STDC__)
#include <stdlib.h>
#include <string.h>
#endif
#define delimiter(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)==';'||(c)=='('||(c)==')'||(c)=='`'||(c)=='|'||(c)=='&'||(c)=='=')
#define KEY(a,b,c,d) ((((unsigned long)(a))<<15)|(((unsigned long)(b))<<10)|(((unsigned long)(c))<<5)|(((unsigned long)(d))))
#define ROTATE(p,l,r,t) ((t)=(p)->l,(p)->l=(t)->r,(t)->r=(p),(p)=(t))
#ifndef S_IXUSR
#endif
#ifndef S_IXGRP
#endif
#ifndef S_IXOTH
#endif
struct Rule_s;
{
} Buf_t;
{
} Dict_item_t;
{
} Dict_t;
{
} List_t;
{
} Rule_t;
{
} Stream_t;
{
} View_t;
static struct /* program state */
{
} state;
extern char** environ;
#if !_PACKAGE_ast
#endif
/*
* emit usage message and exit
*/
static void
usage()
{
fprintf(stderr, "Usage: %s [-iknFKNV] [-f mamfile] [-r pattern] [-C directory] [-D level] [target ...] [name=value ...]\n", state.id);
exit(2);
}
#endif
/*
* output error message identification
*/
static void
{
else
}
/*
* emit error message
* level:
* <0 debug
* 0 info
* 1 warning
* 2 error
* >2 exit(level-2)
*/
static void
{
int i;
{
if (level)
if (level < 0)
{
}
else
{
{
}
if (level == 1)
else if (level > 1)
}
if (item)
if (level > 2)
}
}
/*
* don't know how to make or exit code making
*/
static void
{
if (!code)
else
{
return;
}
if (!keepgoing)
exit(1);
r->flags |= RULE_error;
}
/*
* local strrchr()
*/
static char*
last(register char* s, register int c)
{
register char* r = 0;
for (r = 0; *s; s++)
if (*s == c)
r = s;
return r;
}
/*
* open a buffer stream
*/
static Buf_t*
buffer(void)
{
return buf;
}
/*
* close a buffer stream
*/
static void
{
}
/*
* append str length n to buffer and return the buffer base
*/
static char*
{
int m;
int i;
{
}
}
/*
* append str to buffer and return the buffer base
* if str==0 then next pointer reset to base
*/
static char*
{
if (str)
}
/*
* allocate space for s and return the copy
*/
static char*
duplicate(char* s)
{
char* t;
int n;
n = strlen(s);
if (!(t = newof(0, char, n, 1)))
strcpy(t, s);
return t;
}
/*
* open a new dictionary
*/
static Dict_t*
dictionary(void)
{
return dict;
}
/*
* return the value for item name in dictionary dict
* if value!=0 then name entry value is created if necessary and set
* uses top-down splaying (ala Tarjan and Sleator)
*/
static void*
{
register int cmp;
register Dict_item_t* t;
while (root)
{
break;
else if (cmp < 0)
{
{
if (!cmp)
break;
}
if (right)
else
}
else
{
{
if (!cmp)
break;
}
if (left)
else
}
}
if (root)
{
if (right)
else
if (left)
else
}
else if (value)
{
}
if (root)
{
if (value)
}
if (left)
{
}
else if (right)
{
}
return 0;
}
/*
* low level for walk()
*/
static int
{
do
{
return -1;
return -1;
return 0;
}
/*
* apply func to each dictionary item
*/
static int
{
}
/*
* return a rule pointer for name
*/
static Rule_t*
{
Rule_t* r;
{
}
return r;
}
/*
* prepend p onto rule r prereqs
*/
static void
{
register List_t* x;
if (!x)
{
x->rule = p;
r->prereqs = x;
}
}
/*
* initialize the viewpath
*/
static void
view(void)
{
register char* s;
register char* t;
register char* p;
int c;
int n;
{
}
{
zp = 0;
for (;;)
{
for (t = s; *t && *t != ':'; t++);
if (c = *t)
*t = 0;
{
/*
* determine the viewpath offset
*/
p = ".";
else
{
if (*--p == '/')
{
*p = 0;
*p = '/';
{
p++;
break;
}
}
}
}
n = strlen(s);
else
if (!c)
break;
*t++ = c;
s = t;
}
}
}
/*
* return next '?' or '}' in nested '}'
*/
static char*
cond(register char* s)
{
register int n;
if (*s == '?')
s++;
n = 0;
for (;;)
{
switch (*s++)
{
case 0:
break;
case '{':
n++;
continue;
case '}':
if (!n--)
break;
continue;
case '?':
if (!n)
break;
continue;
default:
continue;
}
break;
}
return s - 1;
}
/*
* expand var refs from s into buf
*/
static void
{
register char* t;
register char* v;
register char* q;
register char* b;
register int c;
register int n;
int a = 0;
int i;
while (c = *s++)
{
if (c == '$' && *s == '{')
{
b = s - 1;
i = 1;
for (n = *(t = ++s) == '-' ? 0 : '-'; (c = *s) && c != '?' && c != '+' && c != n && c != ':' && c != '=' && c != '[' && c != '}'; s++)
if (!isalnum(c) && c != '_')
i = 0;
*s = 0;
if (c == '[')
{
*s = c;
continue;
}
if ((c == ':' || c == '=') && (!v || c == ':' && !*v))
{
*s = c;
continue;
}
if (t[0] == 'A' && t[1] == 'R' && t[2] == 0)
a = 1;
*s = c;
if (c && c != '}')
{
n = 1;
for (t = ++s; *s; s++)
if (*s == '{')
n++;
else if (*s == '}' && !--n)
break;
}
switch (c)
{
case '?':
q = cond(t - 1);
if (v)
{
v = 0;
}
else if (q == t)
v = s;
t = cond(q);
if (v)
{
if (t > q)
{
c = *t;
*t = 0;
*t = c;
}
}
else
{
q = cond(t);
if (q > t)
{
c = *q;
*q = 0;
*q = c;
}
}
break;
case '+':
case '-':
if ((v == 0 || *v == 0) == (c == '-'))
{
c = *s;
*s = 0;
substitute(buf, t);
*s = c;
break;
}
if (c != '-')
break;
/*FALLTHROUGH*/
case 0:
case '=':
case '}':
if (v)
{
if (a && t[0] == 'm' && t[1] == 'a' && t[2] == 'm' && t[3] == '_' && t[4] == 'l' && t[5] == 'i' && t[6] == 'b')
{
for (t = v; *t == ' '; t++);
for (; *t && *t != ' '; t++);
if (*t)
*t = 0;
else
t = 0;
substitute(buf, v);
if (t)
*t = ' ';
}
else
substitute(buf, v);
}
else if (i)
{
c = *s;
*s = 0;
*s = c;
continue;
}
break;
}
if (*s)
s++;
}
else
}
}
/*
* expand var refs from s into buf and return buf base
*/
static char*
{
substitute(buf, s);
}
/*
* stat() with .exe check
*/
static char*
{
int r;
char* s;
return path;
{
off = 0;
}
if (off)
else
if (!buf)
{
s = path;
}
if (r)
{
if (off)
s[off] = 0;
s = 0;
}
return s;
}
/*
* return path to file
*/
static char*
{
char* s;
int node;
int c;
int o;
{
return s;
}
{
node = 0;
if (*file == '/')
{
do
{
{
node = 2;
break;
}
}
else
if (vp)
do
{
if (node)
{
}
else
{
}
{
return s;
}
}
return 0;
}
/*
* bind r to a file and return the modify time
*/
static unsigned long
{
char* s;
{
if (s != r->name)
r->flags |= RULE_exists;
}
return r->time;
}
/*
* pop the current input file
*/
static int
pop(void)
{
int r;
r = 0;
else
else
return r;
}
/*
* push file onto the input stack
*/
static int
{
char* path;
else if (flags & STREAM_PIPE)
{
flags |= STREAM_KEEP;
}
else
{
{
}
else
{
pop();
if (flags & STREAM_MUST)
return 0;
}
}
return 1;
}
/*
* return the next input line
*/
static char*
input(void)
{
char* e;
return 0;
*e = 0;
}
/*
* the -c wrapper ensures that scripts are run in the selected shell
* even on systems that otherwise demand #! magic (can you say cygwin)
*/
static int
execute(register char* s)
{
register int c;
if (!state.shell && (!(state.shell = (char*)search(state.vars, "SHELL", NiL)) || !strcmp(state.shell, sh)))
while (c = *s++)
{
if (c == '\'')
{
for (s--; *s == c; s++)
{
}
}
}
if ((c = system(s)) > 255)
c >>= 8;
return c;
}
/*
* run action s to update r
*/
static unsigned long
{
register Rule_t* q;
register char* t;
register int c;
register View_t* v;
int i;
int j;
int x;
if (r->flags & RULE_error)
return r->time;
{
}
else
if (x)
{
do
{
for (; delimiter(*s); s++)
for (t = s; *s && !delimiter(*s); s++);
c = *s;
*s = 0;
if (c == '=')
{
continue;
}
else
{
if (*t == '-' && *(t + 1) == 'I' && (*(t + 2) || c))
{
if (*(t + 2))
i = 2;
else
{
for (i = 3; *(t + i) == ' ' || *(t + i) == '\t'; i++);
*s = c;
for (s = t + i; *s && *s != ' ' && *s != '\t' && *s != '\n'; s++);
c = *s;
*s = 0;
}
if (*(t + i) && *(t + i) != '/')
{
while (v = v->next)
{
for (j = 0; j < i; j++)
if (*(t + i) != '.' || *(t + i + 1))
{
}
}
}
}
}
} while (*s = c);
}
else if (x)
{
}
if (x)
{
if (c = execute(s))
{
r->flags |= RULE_exists;
}
else
}
else
{
r->flags |= RULE_exists;
}
return r->time;
}
/*
* return the full path for s using buf workspace
*/
static char*
{
register char* p;
register char* d;
register char* x;
char* e;
register int c;
int t;
int o;
for (e = s; *e && *e != ' ' && *e != '\t'; e++);
t = *e;
return x;
do
{
for (d = p; *p && *p != ':'; p++);
c = *p;
*p = 0;
if (*d && (*d != '.' || *(d + 1)))
{
}
*p = c;
if (t)
*e = 0;
if (t)
*e = t;
return x;
} while (*p++);
if (must)
return 0;
}
/*
* generate (if necessary) and read the MAM probe information
* done on the first `setv CC ...'
*/
static void
probe(void)
{
register char* cc;
register char* s;
unsigned long h;
unsigned long q;
cc = "cc";
for (h = 0; *s; s++)
h = h * 0x63c63cd9L + *s + 0x9c39c33dL;
for (h &= 0xffffffffL; h; h >>= 4)
{
}
pop();
}
/*
* add attributes in s to r
*/
static void
{
register char* t;
register int n;
for (;;)
{
for (; *s == ' '; s++);
for (t = s; *s && *s != ' '; s++);
if (!(n = s - t))
break;
switch (*t)
{
case 'd':
r->flags |= RULE_dontcare;
break;
case 'g':
r->flags |= RULE_generated;
break;
case 'i':
r->flags |= RULE_ignore;
r->flags |= RULE_implicit;
break;
case 'v':
r->flags |= RULE_virtual;
break;
}
}
}
/*
* define ${mam_libX} for library reference lib
*/
static char*
{
register int c;
char* s;
char* r;
FILE* f;
if (dynamic < 0)
{
s = 0;
for (;;)
{
if (s)
break;
if (s)
{
r = lib;
break;
}
s = "${INSTALLROOT}/lib/";
if (dynamic)
{
{
r = lib;
break;
}
}
}
if (r != lib)
r = duplicate(r);
{
}
if (f)
{
for (;;)
{
if (c == EOF)
break;
do
{
if (s[0] && (s[0] != '-' || s[1]))
{
}
}
fclose(f);
}
else if (dontcare)
{
r = "";
}
r = duplicate(r);
}
return r;
}
/*
* input() until `done r'
*/
static unsigned long
{
register char* s;
register char* t;
register char* u;
register char* v;
register Rule_t* q;
unsigned long z;
unsigned long x;
r->making++;
if (r->flags & RULE_active)
if (*r->name)
{
z = bind(r);
}
else
z = 0;
cmd = 0;
while (s = input())
{
for (; *s == ' '; s++);
for (; isdigit(*s); s++);
for (; *s == ' '; s++);
for (u = s; *s && *s != ' '; s++);
if (*s)
{
for (*s++ = 0; *s == ' '; s++);
for (t = s; *s && *s != ' '; s++);
if (*s)
for (*s++ = 0; *s == ' '; s++);
v = s;
}
else
t = v = s;
{
if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && (s = require(t, !strcmp(v, "dontcare"))) && strncmp(r->name, "FEATURE/", 8) && strcmp(r->name, "configure.h"))
for (;;)
{
for (t = s; *s && *s != ' '; s++);
if (*s)
*s = 0;
else
s = 0;
if (*t)
{
attributes(q, v);
x = bind(q);
if (z < x)
z = x;
if (q->flags & RULE_error)
r->flags |= RULE_error;
}
if (!s)
break;
for (*s++ = ' '; *s == ' '; s++);
}
continue;
if (q != r)
attributes(r, v);
{
{
if (!r->time)
else
}
if (z < x)
z = x;
}
break;
r->flags |= RULE_generated;
if (r->path)
{
r->path = 0;
r->time = 0;
}
{
if (cmd)
else
}
continue;
if (!q->making)
{
attributes(q, v);
x = make(q);
if (!(q->flags & RULE_ignore) && z < x)
z = x;
if (q->flags & RULE_error)
r->flags |= RULE_error;
}
continue;
if (!q->making)
{
z = q->time;
if (q->flags & RULE_error)
r->flags |= RULE_error;
}
continue;
{
if (*v == '"')
{
s = v + strlen(v) - 1;
if (*s == '"')
{
*s = 0;
v++;
}
}
}
{
probe();
}
continue;
default:
continue;
}
break;
}
if (cmd)
if (*r->name)
{
}
if (r->flags & RULE_active)
r->making--;
return r->time = z;
}
/*
* verify that active targets were made
*/
static int
{
dont(r, 0, 1);
return 0;
}
/*
* return 1 if name is an initializer
*/
static int
{
register char* s;
s++;
else
s = name;
return s[0] == 'I' && s[1] == 'N' && s[2] == 'I' && s[3] == 'T';
}
/*
* update recursion leaf r and its prerequisites
*/
static int
{
register List_t* x;
if (r->leaf)
return 0;
}
/*
* scan makefile prereqs
*/
static int
{
register char* s;
register char* t;
register char* u;
register char* w;
Rule_t* q;
int i;
int j;
int k;
int p;
static char* files[] =
{
"Nmakefile",
"nmakefile",
"Makefile",
"makefile"
};
/*
* drop non-leaf rules
*/
if (!r->leaf)
return 0;
/*
* always make initializers
*/
if (initializer(r->name))
{
update(r);
return 0;
}
for (i = 0; i < elementsof(files); i++)
{
{
while (s = input())
{
j = p = 0;
while (*s)
{
for (k = 1; (i = *s) == ' ' || i == '\t' || i == '"' || i == '\''; s++);
for (t = s; (i = *s) && i != ' ' && i != '\t' && i != '"' && i != '\'' && i != '\\' && i != ':'; s++)
if (i == '/')
t = s + 1;
else if (i == '.' && *(s + 1) != 'c' && *(s + 1) != 'C' && *(s + 1) != 'h' && *(s + 1) != 'H' && t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
*s = 0;
if (*s)
*s++ = 0;
if (!t[0])
k = 0;
else if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && t[2])
{
}
else if (p)
{
if (t[0] == '+' && !t[1])
p = 2;
else if (p == 1)
{
{
}
if (i == ':')
while (*s && (*s == ' ' || *s == '\t'))
s++;
}
}
else if (i == ':')
{
if (j != ':' || !isupper(*t))
k = 0;
else if (!strcmp(t, "PACKAGE"))
{
p = 1;
k = 0;
}
else
for (u = t; *u; u++)
if (isupper(*u))
*u = tolower(*u);
else if (!isalnum(*u))
{
k = 0;
break;
}
}
else if (t[0] != 'l' || t[1] != 'i' || t[2] != 'b')
k = 0;
else
for (u = t + 3; *u; u++)
if (!isalnum(*u))
{
k = 0;
break;
}
if (k && ((q = (Rule_t*)search(state.leaf, t, NiL)) && q != r || *t++ == 'l' && *t++ == 'i' && *t++ == 'b' && *t && (q = (Rule_t*)search(state.leaf, t, NiL)) && q != r))
{
for (t = w = r->name; *w; w++)
if (*w == '/')
t = w + 1;
if (t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
t += 3;
for (u = w = q->name; *w; w++)
if (*w == '/')
u = w + 1;
if (strcmp(t, u))
cons(r, q);
}
j = i;
}
}
pop();
for (s = 0, w = r->name; *w; w++)
if (*w == '/')
s = w;
if (s)
{
{
/*
* foolib : foo : libfoo
*/
*(s - 3) = 0;
if (q && q != r)
cons(r, q);
for (t = w = r->name; *w; w++)
if (*w == '/')
t = w + 1;
if (q && q != r)
cons(r, q);
*(s - 3) = 'l';
}
else if (((s - r->name) != 3 || *(s - 1) != 'b' || *(s - 2) != 'i' || *(s - 3) != 'l') && (*(s + 1) != 'l' || *(s + 2) != 'i' || *(s + 3) != 'b'))
{
/*
*/
s++;
t = s + strlen(s);
while (--t > s)
{
if (q && q != r)
cons(r, q);
}
}
}
break;
}
}
return 0;
}
/*
* descend into op and its prereqs
*/
static int
{
if (!state.active && (!(r->flags & RULE_active) || !(r = (Rule_t*)search(state.leaf, r->name, NiL))))
return 0;
}
/*
* append the non-leaf active targets to state.opt
*/
static int
{
if (r->flags & RULE_active)
{
else
{
}
}
return 0;
}
/*
* recurse on mamfiles in subdirs matching pattern
*/
static int
{
register char* s;
register char* t;
Rule_t* r;
/*
* first determine the MAM subdirs
*/
while (s = input())
{
{
r = rule(s);
t++;
else
t = r->name;
}
}
pop();
/*
* grab the non-leaf active targets
*/
{
}
/*
* scan the makefile and descend
*/
return 0;
}
int
{
register char** e;
register char* s;
register char* t;
register char* v;
int c;
/*
* initialize the state
*/
/*
* parse the options
*/
#if _PACKAGE_ast
for (;;)
{
{
case 'e':
continue;
case 'i':
continue;
case 'k':
continue;
case 'N':
/*FALLTHROUGH*/
case 'n':
continue;
case 'F':
continue;
case 'K':
continue;
case 'V':
exit(0);
case 'f':
continue;
case 'r':
continue;
case 'C':
continue;
case 'D':
continue;
case 'G':
continue;
case 'S':
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
if (error_info.errors)
#else
while ((s = *++argv) && *s == '-')
{
if (*(s + 1) == '-')
{
if (!*(s + 2))
{
argv++;
break;
}
for (t = s += 2; *t && *t != '='; t++);
if (!strncmp(s, "debug-symbols", t - s) && append(state.opt, " -G") || !strncmp(s, "strip-symbols", t - s) && append(state.opt, " -S"))
{
if (*t)
{
v = t + 1;
if (t > s && *(t - 1) == '+')
t--;
c = *t;
*t = 0;
}
else
{
c = 0;
v = "1";
}
if (c)
*t = c;
continue;
}
usage();
break;
}
for (;;)
{
switch (*++s)
{
case 0:
break;
case 'e':
continue;
case 'i':
continue;
case 'k':
continue;
case 'N':
/*FALLTHROUGH*/
case 'n':
continue;
case 'F':
continue;
case 'G':
continue;
case 'K':
continue;
case 'S':
continue;
case 'V':
exit(0);
case 'f':
case 'r':
case 'C':
case 'D':
t = s;
if (!*++s && !(s = *++argv))
{
usage();
}
else
switch (*t)
{
case 'f':
break;
case 'r':
break;
case 'C':
break;
case 'D':
break;
}
break;
default:
case '?':
usage();
break;
}
break;
}
}
#endif
/*
* load the environment
*/
for (e = environ; s = *e; e++)
for (t = s; *t; t++)
if (*t == '=')
{
*t = 0;
*t = '=';
break;
}
/*
* grab the command line targets and variable definitions
*/
while (s = *argv++)
{
for (t = s; *t; t++)
if (*t == '=')
{
v = t + 1;
if (t > s && *(t - 1) == '+')
t--;
c = *t;
*t = 0;
*t = c;
break;
}
if (!*t)
{
/*
* handle a few targets for nmake compatibility
*/
exit(1);
continue;
continue;
}
}
/*
* initialize the views
*/
view();
/*
* recursion drops out here
*/
/*
* read the mamfile(s) and bring the targets up to date
*/
pop();
/*
* verify that active targets were made
*/
/*
* done
*/
}