summaryrefslogtreecommitdiff
path: root/tools/make.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/make.c')
-rw-r--r--tools/make.c2525
1 files changed, 0 insertions, 2525 deletions
diff --git a/tools/make.c b/tools/make.c
deleted file mode 100644
index 0b82cd0..0000000
--- a/tools/make.c
+++ /dev/null
@@ -1,2525 +0,0 @@
-/*
- * This file is part of musl-esp: modified version of Musl libc library.
- * musl-esp in general and this file specifically are available under
- * MIT license. See COPYRIGHT file.
- */
-
-#include "common.h"
-
-enum {
- path_max_len = 4096,
- buf_size = 1024 * 1024,
- buf_static_size = 512,
- hash_table_size = 16 * 1024,
- pat_rules_limit = 16,
- find_body_max_depth = 2
-};
-
-const char *debug_prx = ">>> ";
-
-struct line {
- int linenum;
- struct str str;
-};
-
-struct buf {
- char *start;
- char *end;
- char *cur;
-};
-
-struct augstr {
- struct str str;
- int auxval;
-};
-
-struct strbuf {
- struct augstr *buf;
- int len;
- int size;
-};
-
-struct rule_body {
- struct strbuf prereqs;
- int normal_prereq_count;
-
- struct strbuf *recipes;
-};
-
-struct full_rule {
- struct str *target;
- struct rule_body *rest;
-};
-
-struct rule_details {
- struct rule_body *body;
- struct strbuf targets;
- int patrule;
- int lineno;
-};
-
-enum {
- vs_makefile,
- vs_cmdargs
-};
-
-struct vt_cell {
- struct str vname;
- struct str value;
- char scope;
-};
-
-struct vtable {
- struct vt_cell *buf;
- int cells_occupied;
-};
-
-struct rule_cell {
- struct str *target;
- struct rule_body *body;
-};
-
-struct rtable {
- struct rule_cell *buf;
- int cells_occupied;
-};
-
-struct world {
- char *makefile;
- struct str target;
- char **envp;
-
- int debug_mode;
-
- struct full_rule pat_rules[pat_rules_limit];
- int pat_rule_num;
-
- struct vtable vtable;
- struct rtable rtable;
-};
-
-struct eval_aux {
- int level;
- int linenum;
- struct full_rule *rule;
-
- struct buf *mainbuf;
- struct buf *auxbuf;
- struct world *world;
-};
-
-static void lerror(int line, char *str, ...)
-{
- va_list vl;
-
- eprintf("%s: line %d: ", progname, line);
-
- va_start(vl, str);
- evprintf(str, vl);
-
- print_strz(&stderr, "\n");
- va_end(vl);
- exit(1);
-}
-
-static void strdup(struct str *dest, struct str *src, int with_zero)
-{
- int slen = src->end - src->start;
- int len = slen + (with_zero ? 1 : 0);
- dest->start = malloc(len);
- dest->end = dest->start + slen;
-
- memcpy(dest->start, src->start, slen);
- if (with_zero)
- dest->start[slen] = 0;
-}
-
-#define HASHTABLE_INIT(type) \
-static void type ## _init(struct type *t) \
-{ \
- t->buf = malloc(hash_table_size * sizeof(*t->buf)); \
- t->cells_occupied = 0; \
- memset(t->buf, 0, hash_table_size * sizeof(*t->buf)); \
-}
-
-HASHTABLE_INIT(vtable)
-HASHTABLE_INIT(rtable)
-
-/* FNV-1a */
-static unsigned int calc_hash(struct str *str)
-{
- char *tmp;
- unsigned int h = 2166136261;
- for (tmp = str->start; tmp != str->end; ++tmp) {
- h = h ^ *tmp;
- h *= 16777619;
- }
- return h;
-}
-
-static struct rule_cell *rtable_getcell(struct rtable *t, struct str *key)
-{
- unsigned hash = calc_hash(key);
- int i = hash & (hash_table_size - 1);
- for (;;) {
- if (t->buf[i].target == NULL)
- break;
- else if (streq(key, t->buf[i].target))
- break;
- i = (i + 1) & (hash_table_size - 1);
- }
- return t->buf + i;
-}
-
-static struct vt_cell *vtable_getcell(struct vtable *t, struct str *key)
-{
- unsigned hash = calc_hash(key);
- int i = hash & (hash_table_size - 1);
- for (;;) {
- if (t->buf[i].vname.start == NULL)
- break;
- else if (streq(key, &t->buf[i].vname))
- break;
- i = (i + 1) & (hash_table_size - 1);
- }
- return t->buf + i;
-}
-
-static void vtable_update(struct vtable *vt, struct str *key,
- int alloc_name, struct str *value, char scope)
-{
- struct vt_cell *cell = vtable_getcell(vt, key);
- if (cell->vname.start == NULL) {
- ++vt->cells_occupied;
- if ((double)vt->cells_occupied / hash_table_size >= 0.7)
- error("vtable: threshold reached");
-
- if (alloc_name)
- strdup(&cell->vname, key, 0);
- else
- cell->vname = *key;
- }
- cell->value = *value;
- cell->scope = scope;
-}
-
-static struct str *vtable_find(struct vtable *vt, struct str *key)
-{
- struct vt_cell *tmp = vtable_getcell(vt, key);
- if (tmp->vname.start == NULL)
- return NULL;
- return &tmp->value;
-}
-
-static void rtable_add(struct rtable *rt, struct str *target,
- int alloc_name, struct rule_body *rule)
-{
- struct rule_cell *cell = rtable_getcell(rt, target);
- if (cell->target != NULL)
- error("%S: rule redefinition", target);
- if ((double)rt->cells_occupied / hash_table_size >= 0.7)
- error("rtable: threshold reached");
- if (alloc_name) {
- cell->target = malloc(sizeof(*cell->target));
- strdup(cell->target, target, 0);
- } else {
- cell->target = target;
- }
- cell->body = rule;
- ++rt->cells_occupied;
-}
-
-static int rtable_find(struct rtable *rt, struct str *key,
- struct rule_body **val)
-{
- struct rule_cell *cell = rtable_getcell(rt, key);
- if (cell->target == NULL)
- return 0;
- *val = cell->body;
- return 1;
-}
-
-static char *mmap_makefile(char *fname)
-{
- int fd = open(fname, O_RDONLY, 0);
- struct stat st;
- char *tmp;
-
- if (fd == -1)
- goto syserr;
- if (fstat(fd, &st) == -1)
- goto syserr;
-
- tmp = mmap(NULL, st.size + 1, PROT_READ|PROT_WRITE,
- MAP_PRIVATE, fd, 0);
- if (tmp == (void*)-1)
- goto syserr;
- if (close(fd) == -1)
- goto syserr;
- return tmp;
-syserr:
- syscall_error(fname);
- return NULL; /* unreachable */
-}
-
-static char *strchr(char *s, char c)
-{
- for (; *s; ++s) {
- if (*s == c)
- return s;
- }
- return NULL;
-}
-
-static int readline(char **makefile, struct line *line)
-{
- static int linenum = 1;
- char *tmp = *makefile;
- char *marker = NULL;
-
- for (; *tmp && *tmp != '\n'; ++tmp) {
- if (*tmp == '#' && marker == NULL)
- marker = tmp;
- else if (tmp[0] == '\\' && tmp[1] == '\n') {
- tmp[0] = tmp[1] = ' ';
- ++tmp;
- ++linenum;
- }
- }
-
- if (*tmp == 0) {
- if (tmp == *makefile)
- return 0;
- else
- error("last line missing '\\n'");
- }
-
- *tmp = 0;
- line->linenum = linenum;
- ++linenum;
- line->str.start = *makefile;
- line->str.end = marker ? marker : tmp;
- *makefile = tmp + 1;
-
- return 1;
-}
-
-static int nextline_starts_with_tab(char *file)
-{
- return file[0] == '\t';
-}
-
-#define buf_static_init(buf, local_buf, size) \
-do { \
- buf.start = local_buf; \
- buf.end = buf.start + size; \
- buf.cur = buf.start; \
-} while (0)
-
-static void buf_init(struct buf *buf)
-{
- buf->start = mem_alloc(buf_size);
- buf->end = buf->start + buf_size;
- buf->cur = buf->start;
-}
-
-static void __buf_putchar(struct buf *buf, char c, int inc)
-{
- if (buf->cur == buf->end)
- error("buf_putchar: buffer resizing is not supported");
- if (c == '\t')
- c = ' ';
- if (c == ' ' && buf->cur > buf->start && buf->cur[-1] == ' ')
- return;
- *buf->cur = c;
- if (inc)
- ++buf->cur;
-}
-
-static void buf_putchar(struct buf *buf, char c)
-{
- __buf_putchar(buf, c, 1);
-}
-
-static void buf_put_silent_zero(struct buf *buf)
-{
- __buf_putchar(buf, 0, 0);
-}
-
-static void buf_puts(struct buf *buf, struct str *str)
-{
- char *tmp;
- for (tmp = str->start; tmp != str->end; ++tmp)
- buf_putchar(buf, *tmp);
-}
-
-static void buf_putsz(struct buf *buf, char *s)
-{
- for (; *s; ++s)
- buf_putchar(buf, *s);
-}
-
-static int strempty(struct str *str)
-{
- return str->start == str->end;
-}
-
-static int strlen(struct str *str)
-{
- return str->end - str->start;
-}
-
-static char *find_cparent(int line, struct str *str)
-{
- char *tmp;
- int level = 0;
- for (tmp = str->start + 1; tmp != str->end; ++tmp) {
- if (*tmp == '(')
- ++level;
- if (*tmp == ')') {
- if (level == 0)
- return tmp;
- else
- --level;
- }
- }
- lerror(line, "missing ')'");
- return NULL; /* unreachable */
-}
-
-enum {
- id_variable,
- id_subref,
-
- id_prereqs,
- id_first_prereq,
- id_target,
-
- id_func_class_start,
- id_func_wildcard,
- id_func_subst,
- id_func_patsubst,
- id_func_filter,
- id_func_filter_out,
-
- id_func_basename,
- id_func_dir,
-
- id_func_shell,
- id_func_addprefix,
- id_func_addsuffix,
- id_func_sort,
- id_func_class_end
-};
-
-struct eprofile {
- char type;
- struct str *body;
-
- struct str from;
- struct str to;
-};
-
-static int is_space(char c)
-{
- return c == ' ' || c == '\t';
-}
-
-static int valid_var_char(char c)
-{
- return (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- ( c >= '0' && c <= '9') ||
- c == '_' || c == '/' ||
- c == '-' || c == '.';
-}
-
-static char *word_end(struct str *str)
-{
- char *tmp;
- for (tmp = str->start; tmp != str->end; ++tmp) {
- if (is_space(*tmp))
- return tmp;
- if (!valid_var_char(*tmp))
- return *tmp == ':' ? tmp : NULL;
- }
- return tmp;
-}
-
-#define ENTRY(fname) { CSTR(#fname), id_func_ ## fname }
-
-static struct { struct str fname; char type; } func_table[] = {
- ENTRY(wildcard),
- ENTRY(subst),
- ENTRY(patsubst),
- ENTRY(filter),
- { CSTR("filter-out"), id_func_filter_out },
- ENTRY(basename),
- ENTRY(dir),
- ENTRY(sort),
- ENTRY(shell),
- ENTRY(addprefix),
- ENTRY(addsuffix)
-};
-#undef ENTRY
-
-static int is_special_var(struct eprofile *prof, struct str *word)
-{
- if (streq(word, &CSTR("^"))) {
- prof->type = id_prereqs;
- return 1;
- } else if (streq(word, &CSTR("<"))) {
- prof->type = id_first_prereq;
- return 1;
- } else if (streq(word, &CSTR("@"))) {
- prof->type = id_target;
- return 1;
- }
- return 0;
-}
-
-static void check_var_form(struct str *word, struct str *all,
- int line)
-{
- if (word->end == all->end)
- return;
- lerror(line, "(%S): variable name must be a single word", all);
-}
-
-static void parse_subref(struct eprofile *prof, struct str *vname,
- struct str *all, int line)
-{
- char *tmp;
- prof->type = id_subref;
-
- all->start = vname->end + 1;
- prof->from.start = all->start;
- for (tmp = all->start; tmp != all->end && *tmp != '='; ++tmp)
- ;
- if (tmp == all->end)
- lerror(line, "%s: no '=' is subref expr", vname);
- prof->from.end = tmp;
- prof->to.start = tmp + 1;
- prof->to.end = all->end;
-
- *all = *vname;
- prof->body = all;
-}
-
-static void parse_profile(struct eprofile *prof, struct str *str, int line,
- struct full_rule *rule)
-{
- int i;
- char *wend;
- struct str first_word;
-
- if (rule != NULL && is_special_var(prof, str))
- return;
-
- wend = word_end(str);
- if (wend == NULL)
- lerror(line, "invalid symbol during first word parsing");
- first_word = (struct str) { str->start, wend };
-
- if (wend != str->end && *wend == ':') {
- parse_subref(prof, &first_word, str, line);
- return;
- }
-
- for (i = 0; i < sizeof(func_table) / sizeof(func_table[0]); ++i) {
- if (streq(&first_word, &func_table[i].fname)) {
- prof->type = func_table[i].type;
- str->start = first_word.end;
- prof->body = str;
- return;
- }
- }
- prof->type = id_variable;
- check_var_form(&first_word, str, line);
- prof->body = str;
-}
-
-static void __eval(struct eval_aux *aux, struct str *str);
-
-static void swap_buffers(struct eval_aux *aux)
-{
- struct buf *tmp = aux->mainbuf;
- aux->mainbuf = aux->auxbuf;
- aux->auxbuf = tmp;
-}
-
-static void eval_wrapper(struct eval_aux *aux, struct str *str,
- int swap, int zero_terminate)
-{
- struct str tmp = *str;
- ++aux->level;
- if (swap)
- swap_buffers(aux);
- __eval(aux, &tmp);
- if (zero_terminate)
- buf_put_silent_zero(aux->mainbuf);
- if (swap)
- swap_buffers(aux);
- --aux->level;
-}
-
-static int adjust_vname(struct buf *buf, struct full_rule *rule,
- struct str *vname)
-{
- if (rule == NULL)
- return 0;
- buf_puts(buf, rule->target);
- buf_putchar(buf, '#');
- buf_puts(buf, vname);
- return 1;
-}
-
-static void expand_variable(struct eval_aux *aux, struct eprofile *prof)
-{
- char localbuf[buf_static_size];
- struct buf buf;
- struct str *varval = NULL;
-
- buf_static_init(buf, localbuf, buf_static_size);
- if (adjust_vname(&buf, aux->rule, prof->body)) {
- struct str name = (struct str) { buf.start, buf.cur };
- varval = vtable_find(&aux->world->vtable, &name);
- }
-
- if (varval == NULL)
- varval = vtable_find(&aux->world->vtable, prof->body);
-
- if (varval == NULL)
- return;
- eval_wrapper(aux, varval, 0, 0);
-}
-
-static void expand_first_prereq(struct eval_aux *aux,
- struct eprofile *prof)
-{
- if (aux->rule->rest->prereqs.len == 0)
- return;
- buf_puts(aux->mainbuf, &aux->rule->rest->prereqs.buf[0].str);
-}
-
-static void expand_prereqs(struct eval_aux *aux,
- struct eprofile *prof)
-{
- int i;
- struct strbuf *prereqs = &aux->rule->rest->prereqs;
- for (i = 0; i < prereqs->len; ++i) {
- buf_puts(aux->mainbuf, &prereqs->buf[i].str);
- if (i + 1 != prereqs->len)
- buf_putchar(aux->mainbuf, ' ');
- }
-}
-
-static void trim_front(struct str *str);
-static void trim_back(struct str *str);
-static void trim(struct str *str);
-
-static int extract_word(struct str *str, struct str *word)
-{
- char *tmp;
-
- trim_front(str);
- if (strempty(str))
- return 0;
-
- tmp = str->start;
- word->start = tmp;
- for (; tmp != str->end && !is_space(*tmp); ++tmp)
- ;
- word->end = tmp;
-
- str->start = tmp;
- return 1;
-}
-
-struct matched {
- int front_remains;
- int have_wildcard;
- struct str wildcard;
-};
-
-static char *contains_char(struct str *str, char c);
-
-static int matches_wildcard(struct matched *m, struct str *pat,
- struct str *str, char *wildcard)
-{
- int ret;
- int diff = wildcard - pat->start;
- ret = memeq(str->start, pat->start, diff);
- if (ret == 0)
- return 0;
- if (m)
- m->wildcard.start = str->start + diff;
- diff = pat->end - (wildcard + 1);
- ret = memeq(str->end - diff, pat->end - diff, diff);
- if (ret == 0)
- return 0;
- if (m) {
- m->wildcard.end = str->end - diff;
- m->have_wildcard = 1;
- }
- return 1;
-}
-
-static int match_str(struct str *pat, struct str *str,
- struct matched *m)
-{
- char *tmp;
-
- if (m) {
- m->front_remains = 0;
- m->have_wildcard = 0;
- }
-
- tmp = contains_char(pat, '%');
- if (tmp != NULL) {
- if(!matches_wildcard(m, pat, str, tmp))
- return 0;
- } else {
- int ret;
- int diff = strlen(str) - strlen(pat);
- if (diff < 0)
- return 0;
- ret = memeq(str->start + diff, pat->start, strlen(pat));
- if (ret == 0)
- return 0;
- if (m)
- m->front_remains = diff;
- }
- return 1;
-}
-
-static int pmatches(struct eprofile *prof, struct str *value,
- struct matched *m)
-{
- return match_str(&prof->from, value, m);
-}
-
-static void modify(struct eval_aux *aux, struct eprofile *prof,
- struct str *value, struct matched *m)
-{
- int i;
- char *tmp;
- struct str *template = &prof->to;
- for (i = 0; i < m->front_remains; ++i)
- buf_putchar(aux->mainbuf, value->start[i]);
- for (tmp = template->start; tmp != template->end; ++tmp) {
- if (*tmp == '%' && m->have_wildcard)
- buf_puts(aux->mainbuf, &m->wildcard);
- else
- buf_putchar(aux->mainbuf, *tmp);
- }
-}
-
-static void subref(struct eval_aux *aux, struct eprofile *prof,
- struct str *value)
-{
- int first = 1;
- for (;; first = 0) {
- struct str word;
- struct matched matched;
-
- if (!extract_word(value, &word))
- break;
-
- if (!first)
- buf_putchar(aux->mainbuf, ' ');
-
- if (pmatches(prof, &word, &matched))
- modify(aux, prof, &word, &matched);
- else
- buf_puts(aux->mainbuf, &word);
- }
-}
-
-static void expand_subref(struct eval_aux *aux, struct eprofile *prof)
-{
- char *savedpos = aux->auxbuf->cur;
- char *tmp;
- struct str value;
- prof->type = id_variable;
-
- swap_buffers(aux);
- expand_variable(aux, prof);
- swap_buffers(aux);
- value = (struct str) { savedpos, aux->auxbuf->cur };
-
- tmp = aux->auxbuf->cur;
- eval_wrapper(aux, &prof->from, 1, 0);
- prof->from = (struct str) { tmp, aux->auxbuf->cur };
-
- tmp = aux->auxbuf->cur;
- eval_wrapper(aux, &prof->to, 1, 0);
- prof->to = (struct str) { tmp, aux->auxbuf->cur };
-
- subref(aux, prof, &value);
-
- aux->auxbuf->cur = savedpos;
-}
-
-static void expand_target(struct eval_aux *aux)
-{
- eval_wrapper(aux, aux->rule->target, 0, 0);
-}
-
-static int extract_farg(struct str *src, struct str *arg)
-{
- int level = 0;
- char *tmp;
-
- arg->start = src->start;
- for (tmp = src->start; tmp != src->end; ++tmp) {
- if (*tmp == '(')
- ++level;
- else if (*tmp == ')')
- --level;
- else if (*tmp == ',' && level == 0)
- break;
-
- }
- arg->end = tmp;
- if (tmp == src->end)
- return 0;
- src->start = tmp + 1;
- return 1;
-}
-
-static void basename_word(struct str *res, struct str *word)
-{
- char *tmp = word->end - 1;
- char *dot = NULL;
- for (; tmp >= word->start; --tmp) {
- if (*tmp == '.' && dot == NULL) {
- dot = tmp;
- break;
- }
- if (*tmp == '/')
- break;
- }
- *res = (struct str) {
- word->start,
- dot ? dot : word->end
- };
-}
-
-static void dir_word(struct str *res, struct str *word)
-{
- char *tmp = word->end - 1;
- char *slash = NULL;
-
- for (; tmp >= word->start; --tmp) {
- if (*tmp == '/') {
- slash = tmp;
- break;
- }
- }
- if (slash == NULL)
- *res = CSTR("./");
- else
- *res = (struct str) { word->start, slash + 1 };
-}
-
-static void extract_args(struct str *args, struct str *str, int argnum,
- char *func, int linenum)
-{
- int i;
- for (i = 0;; ++i) {
- int ret = extract_farg(str, args + i);
- if (i == argnum - 1) {
- if (ret == 1)
- goto argcount_err;
- else {
- trim(args + i);
- return;
- }
- }
- if (ret == 0)
- goto argcount_err;
- trim(args + i);
- }
-argcount_err:
- lerror(linenum, "%s expects %d argument%s", func, argnum,
- argnum > 1 ? "s" : "");
-}
-
-enum {
- mode_basename,
- mode_dir,
-};
-
-static void expand_basename_or_dir(struct eval_aux *aux, int mode,
- struct eprofile *prof)
-{
- struct str arg;
- int first = 1;
-
- char *func = mode == mode_basename ? "basename" : "dir";
- extract_args(&arg, prof->body, 1, func, aux->linenum);
-
- for (;; first = 0) {
- struct str word, res;
-
- if(!extract_word(&arg, &word))
- break;
-
- if (mode == mode_basename)
- basename_word(&res, &word);
- else
- dir_word(&res, &word);
- if (!first)
- buf_putchar(aux->mainbuf, ' ');
- buf_puts(aux->mainbuf, &res);
- }
-}
-
-static int arg_is_single_word(struct str *str)
-{
- struct str word;
-
- if (!extract_word(str, &word))
- return 0;
- trim_front(str);
-
- if (!strempty(str))
- return 0;
- *str = word;
- return 1;
-}
-
-enum {
- mode_prefix,
- mode_suffix
-};
-
-static void expand_add(struct eval_aux *aux, int mode,
- struct eprofile *prof)
-{
- struct str args[2];
- int first = 1;
-
- char *func = mode == mode_prefix ? "addprefix" : "addsuffix";
- extract_args(args, prof->body, 2, func, aux->linenum);
-
- if (!arg_is_single_word(args))
- lerror(aux->linenum, "%s: accepts a single prefix", func);
-
- for (;; first = 0) {
- struct str word;
-
- if (!extract_word(args + 1, &word))
- break;
-
- if (!first)
- buf_putchar(aux->mainbuf, ' ');
- if (mode == mode_prefix) {
- buf_puts(aux->mainbuf, args);
- buf_puts(aux->mainbuf, &word);
- } else {
- buf_puts(aux->mainbuf, &word);
- buf_puts(aux->mainbuf, args);
- }
- }
- return;
-}
-
-enum {
- mode_filter,
- mode_filter_out
-};
-
-static int passes_filter(struct str *str, struct strbuf *pats, int mode)
-{
- int ret_when_matches = mode == mode_filter ? 1 : 0;
- int i;
- for (i = 0; i < pats->len; ++i) {
- if (match_str(&pats->buf[i].str, str, NULL))
- return ret_when_matches;
- }
- return !ret_when_matches;
-}
-
-static void sbuf_init(struct strbuf *buf);
-static void sbuf_save(struct strbuf *buf, struct str *str, int aux);
-
-static void collect_words(struct strbuf *buf, struct str *words)
-{
- sbuf_init(buf);
-
- for (;;) {
- struct str word;
- int ret = extract_word(words, &word);
- if (ret == 0)
- break;
- sbuf_save(buf, &word, -1);
- }
-}
-
-static void filter_words(struct str *words, struct strbuf *pats,
- struct eval_aux *aux, int mode)
-{
- int first = 1;
- for (;;) {
- struct str word;
- int ret = extract_word(words, &word);
- if (ret == 0)
- break;
- if (!passes_filter(&word, pats, mode))
- continue;
- if (!first)
- buf_putchar(aux->mainbuf, ' ');
- buf_puts(aux->mainbuf, &word);
- first = 0;
- }
-}
-
-static void expand_filter(struct eval_aux *aux, int mode,
- struct eprofile *prof)
-{
- struct str args[2];
- struct strbuf pats;
-
- char *func = mode == mode_filter ? "filter" : "filter-out";
- extract_args(args, prof->body, 2, func, aux->linenum);
-
- heap_offset_save();
- collect_words(&pats, args);
- filter_words(args + 1, &pats, aux, mode);
- heap_offset_restore();
-}
-
-static void merge(struct augstr *to, struct augstr *from, int n)
-{
- int mid = n/2;
- int i, j, k;
-
- for (k = 0, i = 0, j = mid; i < mid && j < n; ++k) {
- if (strge(&from[j].str, &from[i].str)) {
- to[k].str = from[i].str;
- ++i;
- } else {
- to[k].str = from[j].str;
- ++j;
- }
- }
- if (i < mid) {
- for (; i < mid; ++i, ++k)
- to[k].str = from[i].str;
- } else {
- for (; j < n; ++j, ++k)
- to[k].str = from[j].str;
- }
-}
-
-static void mergesort(struct augstr *array, struct augstr *tmp,
- int n)
-{
- if (n < 2)
- return;
- mergesort(tmp, array, n/2);
- mergesort(tmp + n/2, array + n/2, n - n/2);
- merge(array, tmp, n);
-}
-
-static void sort(struct strbuf *words)
-{
- struct augstr *tmp = malloc(sizeof(*tmp) * words->len);
- int i;
- for (i = 0; i < words->len; ++i)
- tmp[i] = words->buf[i];
-
- mergesort(words->buf, tmp, words->len);
-}
-
-static void uniq(struct strbuf *words)
-{
- int i, j;
- struct augstr *array = words->buf;
- for (i = 0, j = 0; i < words->len; ++i) {
- if (j > 0 && streq(&array[i].str, &array[j-1].str))
- continue;
- array[j].str = array[i].str;
- ++j;
- }
- words->len = j;
-}
-
-static void expand_sort(struct eval_aux *aux, struct eprofile *prof)
-{
- struct strbuf words;
- struct str arg;
- int i;
-
- heap_offset_save();
- extract_args(&arg, prof->body, 1, "sort", aux->linenum);
- collect_words(&words, &arg);
-
- sort(&words);
- uniq(&words);
-
- for (i = 0; i < words.len; ++i) {
- if (i > 0)
- buf_putchar(aux->mainbuf, ' ');
- buf_puts(aux->mainbuf, &words.buf[i].str);
- }
-
- heap_offset_restore();
-}
-
-static void save_shell_stdout(int fd, struct buf *buf)
-{
- char tmpbuf[buf_static_size];
- struct str tmp = { buf->cur };
- int skip_spaces = 1;
- for (;;) {
- int i;
- int ret = read(fd, tmpbuf, buf_static_size);
- if (ret == -1)
- syscall_error("shell output read");
- if (ret == 0)
- break;
- for (i = 0; i < ret; ++i) {
- char c = tmpbuf[i];
- if (tmpbuf[i] == '\n')
- c = ' ';
-
- if (is_space(c)) {
- if (skip_spaces)
- continue;
- } else
- skip_spaces = 1;
- buf_putchar(buf, c);
- }
- }
- tmp.end = buf->cur;
- trim_back(&tmp);
- buf->cur = tmp.end;
- close(fd);
-}
-static void check_status(int status, char *prx);
-
-static void expand_shell(struct eval_aux *aux, struct eprofile *prof)
-{
- struct str arg;
- extract_args(&arg, prof->body, 1, "shell", aux->linenum);
- int pipefds[2];
- int status, pid;
-
- trim_front(&arg);
- if (pipe(pipefds) == -1)
- syscall_error("pipe");
- pid = fork();
- if (pid == -1)
- syscall_error("fork");
- if (pid == 0) {
- char *argv[] = { "/bin/dash", "-c", arg.start, NULL };
- if (dup2(pipefds[1], 1) == -1)
- syscall_error("dup2");
- close(pipefds[1]);
- close(pipefds[0]);
- execve(argv[0], argv, aux->world->envp);
- exit(255);
- }
- close(pipefds[1]);
- save_shell_stdout(pipefds[0], aux->mainbuf);
- wait4(pid, &status, 0, NULL);
- check_status(status, "shell: ");
-}
-
-static void subst(struct buf *buf, struct str *from, struct str *to,
- struct str *word)
-{
- int i = 0;
- int fromlen = strlen(from);
- int n = strlen(word);
- while (i <= n - fromlen) {
- if (memeq(word->start + i, from->start, fromlen)) {
- buf_puts(buf, to);
- i += fromlen;
- } else {
- buf_putchar(buf, word->start[i]);
- ++i;
- }
- }
- for (; i < n; ++i)
- buf_putchar(buf, word->start[i]);
-}
-
-static void expand_subst(struct eval_aux *aux, struct eprofile *prof)
-{
- struct str args[3];
- int first = 1;
-
- extract_args(args, prof->body, 3, "subst", aux->linenum);
-
- if (!arg_is_single_word(args))
- goto single_word_err;
- if (!arg_is_single_word(args + 1))
- goto single_word_err;
-
- for (;; first = 0) {
- struct str word;
- int ret = extract_word(args + 2, &word);
- if (ret == 0)
- break;
- if (!first)
- buf_putchar(aux->mainbuf, ' ');
- subst(aux->mainbuf, args, args + 1, &word);
- }
- return;
-single_word_err:
- lerror(aux->linenum, "subst: from/to must to single words");
-}
-
-static int matches(struct str *pat, struct str *str,
- struct str *wildcard);
-
-static void patsubst(struct buf *buf, struct str *from,
- struct str *to, struct str *words)
-{
- int first = 1;
- for (;; first = 0) {
- struct str word, wildcard;
-
- if (extract_word(words, &word) == 0)
- break;
- if (!first)
- buf_putchar(buf, ' ');
- if (matches(from, &word, &wildcard)) {
- char *tmp;
- for (tmp = to->start; tmp != to->end; ++tmp) {
- if (*tmp == '%')
- buf_puts(buf, &wildcard);
- else
- buf_putchar(buf, *tmp);
- }
- } else {
- buf_puts(buf, &word);
- }
- }
-}
-
-static void expand_patsubst(struct eval_aux *aux, struct eprofile *prof)
-{
- struct str args[3];
- extract_args(args, prof->body, 3, "patsubst", aux->linenum);
-
- if (!arg_is_single_word(args))
- goto single_word_err;
- if (!arg_is_single_word(args + 1))
- goto single_word_err;
- if (!contains_char(args, '%'))
- goto no_wildcard_err;
- if (!contains_char(args + 1, '%'))
- goto no_wildcard_err;
-
- patsubst(aux->mainbuf, args, args + 1, args + 2);
- return;
-
-single_word_err:
- lerror(aux->linenum, "patsubst: from/to must be single words");
-no_wildcard_err:
- lerror(aux->linenum, "patsubst: from/to must contain '%'");
-}
-
-enum {
- max_limbs = 64
-};
-
-struct pathbuf {
- struct str limbuf[max_limbs];
- int limbs;
-
- char buf[path_max_len];
- char *cur;
-
- int add_space;
- int linenum;
-
- struct buf *dest;
-};
-
-static void __pbuf_putchar(struct pathbuf *pbuf, char c, int inc)
-{
- if (pbuf->cur == pbuf->buf + path_max_len)
- error("pathbuf: no more space");
- *pbuf->cur = c;
- if (inc)
- ++pbuf->cur;
-}
-
-static void pbuf_putchar(struct pathbuf *pbuf, char c)
-{
- __pbuf_putchar(pbuf, c, 1);
-}
-
-static void pbuf_put_silent_zero(struct pathbuf *pbuf)
-{
- __pbuf_putchar(pbuf, 0, 0);
-}
-
-static void add_slash(struct pathbuf *pbuf)
-{
- if (pbuf->cur - pbuf->buf > 1 || pbuf->cur[-1] == '.')
- pbuf_putchar(pbuf, '/');
-}
-
-static void pbuf_putlimb(struct pathbuf *pbuf, struct str *limb)
-{
- char *tmp;
- add_slash(pbuf);
- for (tmp = limb->start; tmp != limb->end; ++tmp)
- pbuf_putchar(pbuf, *tmp);
-}
-
-static void pbuf_putlimbz(struct pathbuf *pbuf, char *limb)
-{
- add_slash(pbuf);
- for (; *limb; ++limb)
- pbuf_putchar(pbuf, *limb);
-}
-
-static void skip_slashes(struct str *path)
-{
- char *tmp = path->start;
- for (; tmp != path->end && *tmp == '/'; ++tmp)
- ;
- path->start = tmp;
-}
-
-static void init_beginning(struct pathbuf *pbuf, struct str *path)
-{
- if (path->start[0] == '/') {
- skip_slashes(path);
- pbuf_putchar(pbuf, '/');
- } else {
- pbuf_putchar(pbuf, '.');
- }
-}
-
-static struct str *get_word(struct pathbuf *pbuf)
-{
- if (pbuf->limbs == max_limbs)
- error("pathbuf: too deep nesting");
- return pbuf->limbuf + pbuf->limbs;
-}
-
-static int eat_limb(struct pathbuf *pbuf, struct str *path)
-{
- struct str *dest;
- char *tmp;
- if (strempty(path))
- return 0;
- dest = get_word(pbuf);
- dest->start = path->start;
- for (tmp = path->start; tmp != path->end && *tmp != '/'; ++tmp)
- ;
- dest->end = tmp;
- path->start = tmp;
- skip_slashes(path);
- ++pbuf->limbs;
- return 1;
-}
-
-static void parse_path(struct pathbuf *pbuf, struct str *path)
-{
- init_beginning(pbuf, path);
- while (eat_limb(pbuf, path))
- ;
-}
-
-static int is_pattern(struct str *str)
-{
- char *tmp = str->start;
- for (; tmp != str->end; ++tmp) {
- if (*tmp == '*' || *tmp == '?')
- return 1;
- }
- return 0;
-}
-
-static int is_special(char *dent)
-{
- return dent[0] == '.' &&
- (dent[1] == 0 || (dent[1] == '.' && dent[2] == 0));
-}
-
-static int __match(char *pat, char *str, int line)
-{
- for (; *pat; ++pat) {
- if (*pat == '*') {
- char *sc;
- for (sc = str; ; ++sc) {
- if (__match(pat + 1, sc, line))
- return 1;
- if (*sc == 0)
- return 0;
- }
- } else if (*pat == '?') {
- if (*str)
- ++str;
- else
- return 0;
- } else if (*pat == '[') {
- int ret = 0;
- for (++pat; *pat && *pat != ']'; ++pat) {
- if (*pat == *str)
- ret = 1;
- }
- if (*pat == 0)
- lerror(line, "wildcard missing ']'");
- if (ret == 0)
- return 0;
- ++str;
- } else {
- if (*pat != *str)
- return 0;
- ++str;
- }
- }
- return *str == 0;
-}
-
-static int match_pattern(struct str *pat, char *s, int line)
-{
- char c = *pat->end;
- int ret;
-
- *pat->end = 0;
-
- ret = __match(pat->start, s, line);
-
- *pat->end = c;
- return ret;
-}
-
-static void follow_path(struct pathbuf *pbuf, int start);
-
-static void iterate(struct pathbuf *pbuf, int idx)
-{
- struct dir dir;
-
- heap_offset_save();
-
- pbuf_put_silent_zero(pbuf);
- if (opendir(&dir, pbuf->buf) == 0)
- goto end;
-
- char *cur = pbuf->cur;
- for (;;) {
- struct dirent *dent = readdir(&dir);
- pbuf->cur = cur;
-
- if (dent == NULL)
- break;
- if (is_special(dent->name))
- continue;
-
- int res = match_pattern(pbuf->limbuf + idx, dent->name,
- pbuf->linenum);
- if (res) {
- pbuf_putlimbz(pbuf, dent->name);
- follow_path(pbuf, idx + 1);
- }
- }
- closedir(&dir);
-end:
- heap_offset_restore();
-}
-
-static void commit(struct buf *dest, char *path)
-{
- char *tmp = path[0] == '/' ? path : path + 2;
- buf_putsz(dest, tmp);
-}
-
-static int exists(char *path);
-
-static void follow_path(struct pathbuf *pbuf, int start)
-{
- int i;
- for (i = start; i < pbuf->limbs; ++i) {
- if (is_pattern(pbuf->limbuf + i)) {
- iterate(pbuf, i);
- return;
- } else {
- pbuf_putlimb(pbuf, pbuf->limbuf + i);
- }
- }
- pbuf_put_silent_zero(pbuf);
- if (exists(pbuf->buf)) {
- if (pbuf->add_space)
- buf_putchar(pbuf->dest, ' ');
- commit(pbuf->dest, pbuf->buf);
- pbuf->add_space = 1;
- }
-}
-
-static int wexpand(struct buf *buf, struct str *path, int add_space,
- int linenum)
-{
- static struct pathbuf pbuf;
- pbuf.limbs = 0;
- pbuf.cur = pbuf.buf;
- pbuf.add_space = add_space;
- pbuf.dest = buf;
- pbuf.linenum = linenum;
-
- parse_path(&pbuf, path);
- follow_path(&pbuf, 0);
- return pbuf.add_space;
-}
-
-static void expand_wildcard(struct eval_aux *aux, struct eprofile *prof)
-{
- struct str arg;
- int first = 1;
-
- extract_args(&arg, prof->body, 1, "wildcard", aux->linenum);
- for (;;) {
- struct str word;
- if (extract_word(&arg, &word) == 0)
- break;
- int ret = wexpand(aux->mainbuf, &word, !first,
- aux->linenum);
- if (ret && first)
- first = 0;
- }
-}
-
-static void expand_func(struct eval_aux *aux, struct eprofile *prof)
-{
- char *savedpos = aux->auxbuf->cur;
- eval_wrapper(aux, prof->body, 1, 1);
- prof->body = &(struct str) { savedpos, aux->auxbuf->cur };
-
- switch(prof->type) {
- case id_func_basename:
- expand_basename_or_dir(aux, mode_basename, prof);
- break;
- case id_func_dir:
- expand_basename_or_dir(aux, mode_dir, prof);
- break;
- case id_func_addprefix:
- expand_add(aux, mode_prefix, prof);
- break;
- case id_func_addsuffix:
- expand_add(aux, mode_suffix, prof);
- break;
- case id_func_filter:
- expand_filter(aux, mode_filter, prof);
- break;
- case id_func_filter_out:
- expand_filter(aux, mode_filter_out, prof);
- break;
- case id_func_sort:
- expand_sort(aux, prof);
- break;
- case id_func_shell:
- expand_shell(aux, prof);
- break;
- case id_func_subst:
- expand_subst(aux, prof);
- break;
- case id_func_patsubst:
- expand_patsubst(aux, prof);
- break;
- case id_func_wildcard:
- expand_wildcard(aux, prof);
- break;
- default:
- error("func id=%d not implemented yet", prof->type);
- }
- aux->auxbuf->cur = savedpos;
-}
-
-static void __expand(struct eval_aux *aux, struct eprofile *prof)
-{
- switch(prof->type) {
- case id_variable:
- expand_variable(aux, prof);
- break;
- case id_subref:
- expand_subref(aux, prof);
- break;
- case id_target:
- expand_target(aux);
- break;
- case id_first_prereq:
- expand_first_prereq(aux, prof);
- break;
- case id_prereqs:
- expand_prereqs(aux, prof);
- break;
- default:
- expand_func(aux, prof);
- break;
- }
-}
-
-static void expand(struct eval_aux *aux, struct str *str)
-{
- struct eprofile profile;
- struct str estr;
-
- if (strempty(str))
- lerror(aux->linenum, "stray '$'");
-
- if (*str->start == '(') {
- char *end = find_cparent(aux->linenum, str);
-
- ++str->start;
- estr = (struct str) { str->start, end };
- str->start = end + 1;
- } else {
- estr = (struct str) { str->start, str->start + 1 };
- ++str->start;
- }
- parse_profile(&profile, &estr, aux->linenum, aux->rule);
- __expand(aux, &profile);
-}
-
-static int stop_sym(char c)
-{
- return c == '=' || c == '+' || c == ':';
-}
-
-static void __eval(struct eval_aux *aux, struct str *str)
-{
- while (str->start != str->end) {
- if (stop_sym(*str->start) && aux->level == 0 &&
- aux->rule == NULL)
- {
- return;
- } else if (*str->start == '$') {
- ++str->start;
- expand(aux, str);
- } else {
- buf_putchar(aux->mainbuf, *str->start);
- ++str->start;
- }
- }
-}
-
-static struct buf *evict_buf(struct buf *buf)
-{
- static struct buf tmp;
- tmp = *buf;
- tmp.end = tmp.cur;
- buf->start = buf->cur;
- return &tmp;
-}
-
-static struct buf *eval(struct world *world, struct line *line,
- struct full_rule *rule)
-{
- static char localbuf2[buf_size];
- static struct buf buffers[2] = {
- { NULL, NULL, NULL },
- { NULL, NULL, NULL }
- };
- struct eval_aux aux;
-
- if (buffers[0].start == NULL)
- buf_init(buffers);
- else
- buffers[0].cur = buffers[0].start;
- buf_static_init(buffers[1], localbuf2, buf_size);
-
- aux = (struct eval_aux) {
- 0,
- line->linenum,
- rule,
- buffers, buffers + 1,
- world
- };
- __eval(&aux, &line->str);
- buf_putchar(buffers, ' ');
-
- return rule == NULL ? evict_buf(buffers) : buffers;
-}
-
-static void trim_front(struct str *str)
-{
- for (; str->start != str->end; ++str->start) {
- if (!is_space(*str->start))
- break;
- }
-}
-
-static void trim_back(struct str *str)
-{
- for (; str->start != str->end; --str->end) {
- if (!is_space(str->end[-1]))
- break;
- }
-}
-
-static void trim(struct str *str)
-{
- trim_front(str);
- trim_back(str);
-}
-
-static int valid_var_name(struct str *vname)
-{
- char *tmp;
- for (tmp = vname->start; tmp != vname->end; ++tmp) {
- if (!valid_var_char(*tmp))
- return 0;
- }
- return 1;
-}
-
-static void str_combine(struct str *res, struct str *s1, struct str *s2)
-{
- int len1, len2, nlen;
-
- if (s1 == NULL) {
- *res = *s2;
- return;
- }
- len1 = strlen(s1);
- len2 = strlen(s2);
- nlen = len1 + len2 + 1;
-
- res->start = malloc(nlen);
- res->end = res->start + nlen;
-
- memcpy(res->start, s1->start, len1);
- res->start[len1] = ' ';
- memcpy(res->start + len1 + 1, s2->start, len2);
-}
-
-enum {
- svmode_set,
- svmode_append
-};
-
-static void make_full_vname(struct buf *dest, struct str *prx,
- struct str *vname)
-{
- dest->cur = dest->start;
- buf_puts(dest, prx);
- buf_putchar(dest, '#');
- buf_puts(dest, vname);
-}
-
-struct variable {
- struct str name;
- struct strbuf *goals;
- struct str *value;
- char scope;
-
- int linenum;
- struct vtable *vt;
-};
-
-static int check_policy(struct variable *var, struct str *name)
-{
- struct vt_cell *cell = vtable_getcell(var->vt, name);
- if (cell->vname.start == NULL)
- return 1;
-
- if (var->scope == vs_makefile) {
- if (cell->scope == vs_makefile)
- lerror(var->linenum, "%S: variable redefinition",
- name);
- return 0;
- }
- return 1;
-}
-
-static void set_single_var(struct variable *var, struct str *goal, int mode)
-{
- static char localbuf[buf_static_size];
- struct buf buf;
- struct str fullname;
- /* TODO: Why do we need to alloc for goal specific assignments */
- int alloc = goal ? 1 : 0;
-
- buf_static_init(buf, localbuf, buf_static_size);
-
- if (goal != NULL) {
- make_full_vname(&buf, goal, &var->name);
- fullname = (struct str) { buf.start, buf.cur };
- } else {
- fullname = var->name;
- }
-
- if (mode == svmode_set) {
- if (check_policy(var, &fullname) == 0)
- return;
- /* Double work, but I do not think we should even bother */
- vtable_update(var->vt, &fullname, alloc, var->value, var->scope);
- } else {
- struct str newval;
- struct str *oldval = vtable_find(var->vt, &fullname);
- if (oldval == NULL)
- oldval = vtable_find(var->vt, &var->name);
- str_combine(&newval, oldval, var->value);
- vtable_update(var->vt, &fullname, alloc, &newval, var->scope);
- }
-}
-
-static void setvar(struct variable *var, int mode)
-{
- trim(var->value);
-
- if (var->goals != NULL) {
- int i;
- for (i = 0; i < var->goals->len; ++i)
- set_single_var(var, &var->goals->buf[i].str, mode);
- } else {
- set_single_var(var, NULL, mode);
- }
-}
-
-static int is_followed(struct line *line, char c)
-{
- return strlen(&line->str) >= 2 && line->str.start[1] == c;
-}
-
-static void follows(struct line *line, char c)
-{
- if (is_followed(line, c))
- return;
- lerror(line->linenum, "expected %c after %c", c,
- line->str.start[0]);
-}
-
-static void parse_assignment(struct world *world, struct strbuf *goals,
- struct buf *buf, struct line *line, char scope)
-{
- struct variable var = {
- { buf->start, buf->cur },
- goals,
- &line->str,
- scope,
-
- line->linenum,
- &world->vtable
- };
-
- trim(&var.name);
- if (!valid_var_name(&var.name)) {
- lerror(line->linenum, "[%S]: invalid variable name",
- &var.name);
- }
- if (var.value->start[0] == '+') {
- follows(line, '=');
- var.value->start += 2;
- setvar(&var, svmode_append);
- } else {
- ++var.value->start;
- setvar(&var, svmode_set);
- }
-}
-
-static void sbuf_init(struct strbuf *buf)
-{
- buf->size = 1;
- buf->len = 0;
- buf->buf = malloc(sizeof(*buf->buf) * buf->size);
-}
-
-static void sbuf_save(struct strbuf *buf, struct str *str, int aux)
-{
- if (buf->len == buf->size) {
- buf->size *= 2;
- realloc(buf->buf, sizeof(*buf->buf) * buf->size);
- }
- buf->buf[buf->len].str = *str;
- buf->buf[buf->len].auxval = aux;
- ++buf->len;
-}
-
-static int valid_target_char(char c)
-{
- return valid_var_char(c) || c == '%';
-}
-
-static void save_word(struct strbuf *buf, struct str *str, int line)
-{
- struct str word;
- word.start = str->start;
-
- /* No check for empty string here, because str is part of eval
- * result. It won't be overwritten in this case. And at the end
- * of eval we add ' ' for this function.
- */
- for (;; ++str->start) {
- if (is_space(*str->start) || *str->start == ':')
- break;
- if (!valid_target_char(*str->start))
- goto err;
- }
- word.end = str->start;
- *str->start = 0;
- ++str->start;
-
- sbuf_save(buf, &word, line);
- return;
-err:
- lerror(line, "%c: invalid target/prereq name symbol", *str->start);
-}
-
-static void parse_targets(struct strbuf *targets, struct buf *buf, int line)
-{
- struct str str = { buf->start, buf->cur };
- sbuf_init(targets);
-
- for (;;) {
- trim_front(&str);
- if (strempty(&str))
- break;
- save_word(targets, &str, -1);
- }
- if (targets->len == 0)
- lerror(line, "zero targets before ':'");
-}
-
-static void parse_prereqs(struct rule_body *rule, struct buf *buf)
-{
- struct str str = { buf->start, buf->cur };
- sbuf_init(&rule->prereqs);
- int i = 0;
- int normal = -1;
-
- for (;;) {
- trim_front(&str);
- if (strempty(&str))
- break;
- if (*str.start == '|' && normal == -1) {
- normal = i;
- ++str.start;
- trim_front(&str);
- }
- save_word(&rule->prereqs, &str, -1);
- ++i;
- }
- rule->normal_prereq_count = normal == -1 ? i : normal;
-}
-
-static struct strbuf *parse_recipes(char **file)
-{
- struct strbuf *tmp = malloc(sizeof(*tmp));
- sbuf_init(tmp);
-
- while (nextline_starts_with_tab(*file)) {
- struct line line;
- readline(file, &line);
-
- trim(&line.str);
- sbuf_save(tmp, &line.str, line.linenum);
- }
- return tmp;
-}
-
-static void save_first_target(struct world *world,
- struct rule_details *rule)
-{
- if (!strempty(&world->target) || rule->patrule ||
- streq(&rule->targets.buf->str, &CSTR(".PRECIOUS")))
- {
- return;
- }
- world->target = rule->targets.buf->str;
-}
-
-static char *contains_char(struct str *str, char c)
-{
- char *tmp;
- for (tmp = str->start; tmp != str->end; ++tmp) {
- if (*tmp == c)
- return tmp;
- }
- return NULL;
-}
-
-static int is_patrule(struct strbuf *targets, int line)
-{
- if (contains_char(&targets->buf[0].str, '%') == NULL)
- return 0;
- if (targets->len == 1)
- return 1;
- lerror(line, "multiple targets not supported in patturn rules");
- return -1; /* unreachable */
-}
-
-static void add_patrule(struct world *world, struct rule_details *rule)
-{
- if (world->pat_rule_num == pat_rules_limit)
- lerror(rule->lineno, "pattern rules limit reached");
- world->pat_rules[world->pat_rule_num] = (struct full_rule) {
- &rule->targets.buf[0].str,
- rule->body
- };
- ++world->pat_rule_num;
-}
-
-static void handle_normal(struct world *world, struct rule_details *rule,
- struct buf *buf)
-{
- int i;
- parse_prereqs(rule->body, buf);
- rule->body->recipes = parse_recipes(&world->makefile);
-
- if (rule->patrule) {
- add_patrule(world, rule);
- return;
- }
-
- for (i = 0; i < rule->targets.len; ++i) {
- if (streq(&rule->targets.buf[i].str, &CSTR(".PRECIOUS")))
- continue;
- rtable_add(&world->rtable, &rule->targets.buf[i].str, 0,
- rule->body);
- }
-}
-
-char *target_spec_in_patrules =
- "target-specific var in pattern rules are not supported";
-
-static void handle_target_spec(struct world *world, struct buf *buf,
- struct line *line, struct rule_details *rule)
-{
- if (rule->patrule)
- lerror(line->linenum, target_spec_in_patrules);
- if (*line->str.start == ':')
- lerror(line->linenum, "expected target-specific var");
-
- parse_assignment(world, &rule->targets, buf, line, vs_makefile);
-}
-
-static void parse_rule(struct world *world, struct buf *buf,
- struct line *line)
-{
- struct rule_details rule;
-
- ++line->str.start;
- rule.body = malloc(sizeof(*rule.body));
- rule.lineno = line->linenum;
-
- parse_targets(&rule.targets, buf, line->linenum);
- rule.patrule = is_patrule(&rule.targets, line->linenum);
-
- buf = eval(world, line, NULL);
- if (strempty(&line->str))
- handle_normal(world, &rule, buf);
- else
- handle_target_spec(world, buf, line, &rule);
-
- save_first_target(world, &rule);
-}
-
-static int parse_toplev(struct world *world)
-{
- struct line line;
- struct buf *buf;
-
- if (!readline(&world->makefile, &line))
- return 0;
- buf = eval(world, &line, NULL);
-
- if (strempty(&line.str)) {
- struct str tmp = { buf->start, buf->cur };
- trim(&tmp);
- if (!strempty(&tmp))
- lerror(line.linenum, "missing separator");
- } else if (*line.str.start == ':') {
- parse_rule(world, buf, &line);
- } else {
- parse_assignment(world, NULL, buf, &line, vs_makefile);
- }
- return 1;
-}
-
-static void parse(struct world *world)
-{
- while (parse_toplev(world))
- ;
-}
-
-static void world_init(struct world *world, char **envp)
-{
- world->envp = envp;
-
- world->pat_rule_num = 0;
-
- vtable_init(&world->vtable);
- rtable_init(&world->rtable);
-}
-
-static int timegt(struct time *t1, struct time *t2)
-{
- if (t1->sec > t2->sec)
- return 1;
- if (t1->sec == t2->sec)
- return t1->usec > t2->usec;
- return 0;
-}
-
-static void check_status(int status, char *prx)
-{
- if (WIFEXITED(status)) {
- int ret = WEXITSTATUS(status);
- if (ret != 0) {
- error("%s: program exited with %d status",
- prx, ret);
- }
- } else if(WIFSIGNALED(status)) {
- error("%s: program received a signal %d",
- WTERMSIG(status), prx);
- } else {
- error("%s: unknown program status", prx);
- }
-}
-
-static void exec_recipe(struct world *world, struct full_rule *rule,
- int i)
-{
- char *argv[] = { "/bin/sh", "-c", NULL, NULL };
- int ret;
- int status;
- struct augstr *astr = rule->rest->recipes->buf + i;
- struct line line = { astr->auxval, astr->str };
-
- struct buf *buf = eval(world, &line, rule);
- buf_put_silent_zero(buf);
-
- argv[2] = buf->start;
- flush(&stderr);
- ret = fork();
-
- if (ret == -1)
- syscall_error("fork");
- if (ret == 0) {
- struct str cmd = { buf->start, buf->cur };
- trim(&cmd);
- printf("%S\n", &cmd);
- execve("/bin/sh", argv, world->envp);
-
- perror("execve");
- flush(&stderr);
- exit(1);
- }
- wait4(ret, &status, 0, 0);
- check_status(status, "");
-}
-
-static void exec_recipes(struct world *world, struct full_rule *rule)
-{
- int i;
- for (i = 0; i < rule->rest->recipes->len; ++i)
- exec_recipe(world, rule, i);
-}
-
-static int exists(char *path)
-{
- return access(path, F_OK) == 0;
-}
-
-static int matches(struct str *pat, struct str *str,
- struct str *wildcard)
-{
- char *tmp = pat->start;
- char *stmp = str->start;
- int rem;
- for (;*tmp != '%'; ++tmp, ++stmp) {
- if (*tmp != *stmp)
- return 0;
- }
- ++tmp;
-
- rem = pat->end - tmp;
- if (rem > str->end - stmp)
- return 0;
- wildcard->start = stmp;
- wildcard->end = str->end - rem;
- return memeq(tmp, wildcard->end, rem);
-}
-
-static void heapbuf_init(struct buf *buf)
-{
- buf->start = malloc(1);
- buf->cur = buf->start;
- buf->end = buf->start + 1;
-}
-
-static void heapbuf_putchar(struct buf *buf, char c)
-{
- if (buf->cur == buf->end) {
- ++buf->end;
- realloc(buf->start, buf->end - buf->start);
- }
- *buf->cur = c;
- ++buf->cur;
-}
-
-static void heapbuf_puts(struct buf *buf, struct str *str)
-{
- char *tmp;
- for (tmp = str->start; tmp != str->end; ++tmp)
- heapbuf_putchar(buf, *tmp);
-}
-
-static void subst_pat(struct str *dest, struct str *pat,
- struct str *wildcard)
-{
- struct buf buf;
- char *tmp;
- heapbuf_init(&buf);
- for (tmp = pat->start; tmp != pat->end; ++tmp) {
- if (*tmp != '%')
- heapbuf_putchar(&buf, *tmp);
- else
- heapbuf_puts(&buf, wildcard);
- }
- dest->start = buf.start;
- dest->end = buf.cur;
- heapbuf_putchar(&buf, 0);
-}
-
-static struct rule_body *construct_prereqs(struct full_rule *patrule,
- struct str *wildcard)
-{
- struct rule_body *newbody = malloc(sizeof(*newbody));
- struct strbuf *prereqs = &newbody->prereqs;
- int i;
-
- newbody->normal_prereq_count = patrule->rest->normal_prereq_count;
- newbody->recipes = patrule->rest->recipes;
-
- prereqs->len = patrule->rest->prereqs.len;
- prereqs->buf = malloc(sizeof(*prereqs->buf) * prereqs->len);
- for (i = 0; i < prereqs->len; ++i) {
- subst_pat(&prereqs->buf[i].str,
- &patrule->rest->prereqs.buf[i].str, wildcard);
- }
- return newbody;
-}
-
-static void ccarena_grow(struct arena *a, int size)
-{
- error("ccarena: no more space");
-}
-
-void prereqdup(struct arena *a, struct str *dest, struct str *src)
-{
- int len = strlen(src);
- dest->start = amalloc(a, len + 1);
- dest->end = dest->start + len;
- memcpy(dest->start, src->start, len);
- *dest->end = 0;
-}
-
-static struct rule_body *create_copy(struct rule_body *rule_body)
-{
- static struct arena ccarena;
- struct rule_body *tmp;
- struct strbuf *prereqs;
- int i;
- if (ccarena.start == NULL) {
- ccarena.start = ccarena.cur = mem_alloc(buf_size);
- ccarena.end = ccarena.start + buf_size;
- ccarena.grow = ccarena_grow;
- }
- tmp = amalloc(&ccarena, sizeof(*tmp));
- tmp->normal_prereq_count = rule_body->normal_prereq_count;
- tmp->recipes = rule_body->recipes;
- prereqs = &tmp->prereqs;
- prereqs->len = rule_body->prereqs.len;
- prereqs->buf =
- amalloc(&ccarena, sizeof(*prereqs->buf) * prereqs->len);
-
- for (i = 0; i < prereqs->len; ++i) {
- prereqdup(&ccarena, &prereqs->buf[i].str,
- &rule_body->prereqs.buf[i].str);
- }
- /*printf(">>> Cur: %d\n", ccarena.cur - ccarena.start);*/
- return tmp;
-}
-
-static struct rule_body *find_body(struct world *world, struct str *target,
- int depth);
-
-static struct rule_body *suitable_patrule(struct world *world, int idx,
- struct str *target, int depth)
-{
- struct rule_body *tmp = NULL;
- struct rule_body *tmp_copy;
- struct str wildcard;
- int i;
-
- heap_offset_save();
-
- if (!matches(world->pat_rules[idx].target, target, &wildcard))
- goto failure;
-
- tmp = construct_prereqs(world->pat_rules + idx, &wildcard);
-
- for (i = 0; i < tmp->prereqs.len; ++i) {
- struct str *prereq = &tmp->prereqs.buf[i].str;
- struct rule_body *pbody;
- if (exists(prereq->start))
- continue;
- pbody = find_body(world, prereq, depth);
- if (pbody == NULL)
- goto failure;
- }
- tmp_copy = create_copy(tmp);
- /*printf(">>> Saving: %S\n", target);*/
- rtable_add(&world->rtable, target, 1, tmp_copy);
- heap_offset_remove();
- return tmp_copy;
-failure:
- heap_offset_restore();
- return NULL;
-}
-
-static struct rule_body *find_body(struct world *world,
- struct str *target, int depth)
-{
- int i;
- struct rule_body *tmp;
- /*printf("FB: %S\n", target);*/
- if (rtable_find(&world->rtable, target, &tmp) == 1)
- return tmp;
-
- if (depth >= find_body_max_depth)
- return NULL;
-
- for (i = 0; i < world->pat_rule_num; ++i) {
- tmp = suitable_patrule(world, i, target, depth + 1);
- if (tmp != NULL)
- break;
- }
- if (tmp == NULL)
- rtable_add(&world->rtable, target, 1, NULL);
- return tmp;
-}
-
-struct target_info {
- struct time mtime;
- int exists;
-};
-
-static int get_mtime(struct str *str, struct time *time)
-{
- int ret;
- struct stat st;
-
- ret = stat(str->start, &st);
- /*printf("Time: %s %d\n", str->start, ret);*/
- if (ret == -1) {
- if (errno == ENOENT) {
- return 0;
- }
- syscall_error(str->start);
- }
- *time = st.mtime;
- return 1;
-}
-
-static void tinfo_get(struct target_info *info, struct str *str)
-{
- info->exists = get_mtime(str, &info->mtime);
-}
-
-static int exec_target(struct world *world, struct str *target,
- struct target_info *info);
-
-struct pstatus {
- struct time time;
- struct str *prereq;
-};
-
-static int exec_prereqs(struct world *world, struct full_rule *rule,
- struct pstatus *pstatus, struct target_info *info)
-{
- int i;
- int flag = 0;
- struct target_info pinfo;
-
- *pstatus = (struct pstatus) { { 0, 0 }, NULL };
-
- for (i = 0; i < rule->rest->prereqs.len; ++i) {
- int ret, is_oo;
- struct str *prereq = &rule->rest->prereqs.buf[i].str;
- tinfo_get(&pinfo, prereq);
- ret = exec_target(world, prereq, &pinfo);
- is_oo = i >= rule->rest->normal_prereq_count;
- if (ret) {
- if (flag == 0)
- pstatus->prereq = prereq;
- flag = 1;
- }
- if (flag == 0 && !is_oo && timegt(&pinfo.mtime, &pstatus->time)) {
- pstatus->time = pinfo.mtime;
- pstatus->prereq = prereq;
- }
- }
- return flag;
-}
-
-static void print_reason(int debug, struct str *target, int flag,
- struct target_info *info, struct pstatus *ptime)
-{
-
- if (debug == 0)
- return;
- if (!info->exists) {
- printf("%s%S did not exist\n", debug_prx, target);
- } else if (flag) {
- printf("%s%S(%U.%U) by %S\n", debug_prx, target,
- info->mtime.sec, info->mtime.usec,
- ptime->prereq);
- } else {
- printf("%s%S(%U.%U) <- %S(%U.%U)\n", debug_prx, target,
- info->mtime.sec, info->mtime.usec,
- ptime->prereq, ptime->time.sec,
- ptime->time.usec);
- }
-}
-
-static void print_new_time(int debug, struct str *target)
-{
- struct time time;
- if (debug == 0)
- return;
- if (get_mtime(target, &time)) {
- printf("%sUpdated time %S: %U.%U\n", debug_prx, target,
- time.sec, time.usec);
- } else {
- printf("%s%S was not created\n", debug_prx, target);
- }
-}
-
-static int exec_target(struct world *world, struct str *target,
- struct target_info *info)
-{
- struct rule_body *prule = find_body(world, target, 0);
- struct full_rule rule = { target, prule };
- int flag = 0;
- struct pstatus pstatus;
- int prereq_later;
-
- /*printf("EXEC: %S\n", target);*/
- if (prule == NULL) {
- if (info->exists) {
- return 0;
- } else {
- error("%S: don't know what to do with the target",
- target);
- }
- }
- flag = exec_prereqs(world, &rule, &pstatus, info);
-
- prereq_later = timegt(&pstatus.time, &info->mtime);
- if (flag || !info->exists || prereq_later) {
- print_reason(world->debug_mode, target, flag, info,
- &pstatus);
- exec_recipes(world, &rule);
- print_new_time(world->debug_mode, target);
- return 1;
- }
- return 0;
-}
-
-static void exec(struct world *world)
-{
- struct target_info info;
- if (strempty(&world->target)) {
- printf("nothing to be done");
- hexit(0);
- }
- tinfo_get(&info, &world->target);
- exec_target(world, &world->target, &info);
-}
-
-static int is_assignment(char *arg, char **equal_sign)
-{
- char *tmp = strchr(arg, '=');
- if (tmp == NULL)
- return 0;
- *equal_sign = tmp;
- return 1;
-}
-
-static void parse_cmdarg_assignment(struct world *world, char *arg,
- char *equal_sign)
-{
- struct buf buf = { arg, equal_sign, equal_sign };
- char *end = equal_sign + strzlen(equal_sign);
- struct line line = { 0, { equal_sign, end } };
-
- parse_assignment(world, NULL, &buf, &line, vs_cmdargs);
-}
-
-static void parse_cmdargs(struct world *world, char **argv)
-{
- char *makefile = "Makefile";
- char *target = NULL;
- char *equal_sign;
-
- ++argv;
- for (; argv[0]; ++argv) {
- if (argv[0][0] == '-') {
- if (argv[0][1] == 'f' && argv[0][2] == 0) {
- if (argv[1] == NULL)
- error("-f: missing file name");
- makefile = argv[1];
- ++argv;
- } else if (argv[0][1] == 'C' && argv[0][2] == 0) {
- if (argv[1] == NULL)
- error("-C: missing dir");
- if (chdir(argv[1]) == -1)
- syscall_error(argv[1]);
- ++argv;
- } else if (argv[0][1] == 'd' && argv[0][2] == 0) {
- world->debug_mode = 1;
- } else {
- error("%s: unknown flag", argv[0]);
- }
- } else if (is_assignment(argv[0], &equal_sign)) {
- parse_cmdarg_assignment(world, argv[0],
- equal_sign);
- } else {
- if (target)
- error("%s: target already provided");
- target = argv[0];
- }
- }
- world->makefile = mmap_makefile(makefile);
- world->target = target ? STR(target) : CSTR("");
-}
-
-static void print_program_time(int debug)
-{
- struct rusage rusage;
- if (!debug)
- return;
- if (getrusage(RUSAGE_SELF, &rusage) == -1)
- syscall_error("rusage");
- printf("%s: user time: %U.%3U, sys time: %U.%3U\n", progname,
- rusage.utime.sec, rusage.utime.msec / 1000,
- rusage.stime.sec, rusage.stime.msec / 1000);
-}
-
-int main(int argc, char **argv, char **envp)
-{
- struct world world;
-
- world_init(&world, envp);
- parse_cmdargs(&world, argv);
-
- parse(&world);
-
- exec(&world);
- print_program_time(world.debug_mode);
- return 0;
-}