static string_ty * sa_close(void) { string_ty *s; s = str_n_from_c(sa_data, sa_data_length); sa_data_length = 0; return s; }
string_ty * sa_close(stracc *sap) { string_ty *val; trace(("sa_close()\n{\n")); assert(sap->sa_inuse); val = str_n_from_c(sap->sa_buf, sap->sa_len); sap->sa_inuse = 0; trace(("return %08lX;\n", val)); trace(("}\n")); return val; }
static string_ty * ends_with(string_ty *s1, const char *s2) { size_t len2; len2 = strlen(s2); if ( s1->str_length > len2 && 0 == memcmp(s1->str_text + s1->str_length - len2, s2, len2) ) return str_n_from_c(s1->str_text, s1->str_length - len2); return 0; }
string_ty * str_field(string_ty *s, int sep, int fldnum) { char *cp; char *ep; cp = s->str_text; while (fldnum > 0) { ep = strchr(cp, sep); if (!ep) return 0; cp = ep + 1; --fldnum; } ep = strchr(cp, sep); if (ep) return str_n_from_c(cp, ep - cp); return str_from_c(cp); }
int main(int argc, char **argv) { int retval; /* * Some versions of cron(8) and at(1) set SIGCHLD to SIG_IGN. * This is kinda dumb, because it breaks assumprions made in * libc (like pclose, for instance). It also blows away most * of Cook's process handling. We explicitly set the SIGCHLD * signal handling to SIG_DFL to make sure this signal does what * we expect no matter how we are invoked. */ #ifdef SIGCHLD signal(SIGCHLD, SIG_DFL); #else signal(SIGCLD, SIG_DFL); #endif /* * initialize things * (order is critical here) */ progname_set(argv[0]); str_initialize(); id_initialize(); lex_initialize(); /* * parse the COOK environment variable */ arglex_init_from_env(argv[0], argtab); argparse(OPTION_LEVEL_ENVIRONMENT); /* * parse the command line */ arglex_init(argc, argv, argtab); argparse(OPTION_LEVEL_COMMAND_LINE); option_tidy_up(); log_open(); /* * turn on progress stars if they asked for them */ if (option_test(OPTION_STAR)) star_enable(); /* * If we were asked to update the fingerprints, do it here. * We don't actually ant to read in the cookbook. */ if (option.fingerprint_update) { fp_tweak(); quit(0); } /* * read in the cook book * * If there are #include-cooked directives, * we may need to do it more than once. */ if (!option.o_book) fatal_intl(0, i18n("no book found")); for (;;) { int status; size_t j; builtin_initialize(); /* * instanciate the command line variable assignments */ for (j = 0; j < option.o_vardef.nstrings; ++j) { char *s; char *cp; string_ty *name; string_ty *value; string_list_ty wl; opcode_context_ty *ocp; s = option.o_vardef.string[j]->str_text; cp = strchr(s, '='); assert(cp); if (!cp) continue; name = str_n_from_c(s, cp - s); value = str_from_c(cp + 1); str2wl(&wl, value, (char *)0, 0); str_free(value); ocp = opcode_context_new(0, 0); opcode_context_id_assign(ocp, name, id_variable_new(&wl), 0); opcode_context_delete(ocp); str_free(name); string_list_destructor(&wl); } set_command_line_goals(); parse(option.o_book); status = cook_auto_required(); if (status < 0) quit(1); if (!status) break; id_reset(); cook_reset(); } /* * work out what to cook. * If no targets have been given, use the first explicit recipe. */ set_command_line_goals(); if (!option.o_target.nstrings) cook_find_default(&option.o_target); assert(option.o_target.nstrings); /* * cook the target */ if (option.pairs) retval = cook_pairs(&option.o_target); else if (option.script) retval = cook_script(&option.o_target); else if (option.web) retval = cook_web(&option.o_target); else retval = cook(&option.o_target); #ifdef DEBUG fflush_slowly_report(); #endif quit(retval); /*NOTREACHED*/ return 0; }
string_ty * flatten(string_ty *filename) { string_list_ty sl; static string_ty *root; static string_ty *dot; static string_ty *dotdot; size_t pos; size_t start; size_t j; string_ty *s; /* * Create some things we are going to need. */ if (!root) { root = str_from_c(""); dot = str_from_c("."); dotdot = str_from_c(".."); } /* * leading slash is special */ pos = 0; string_list_constructor(&sl); if (filename->str_text[0] == '/') { ++pos; string_list_append(&sl, root); } /* * Break it into slash-separaed words. */ for (;;) { while (pos < filename->str_length && filename->str_text[pos] == '/') ++pos; if (pos >= filename->str_length) break; start = pos; for (;;) { ++pos; if (pos >= filename->str_length || filename->str_text[pos] == '/') break; } /* * remember each word (except ".") */ s = str_n_from_c(filename->str_text + start, pos - start); if (!str_equal(s, dot)) string_list_append(&sl, s); str_free(s); } /* * Try as hard as possible to chuck out redundant stuff. */ for (;;) { int changed = 0; /* * "/.." -> "/" */ if ( sl.nstrings >= 2 && str_equal(sl.string[0], root) && str_equal(sl.string[1], dotdot) ) { string_list_remove_nth(&sl, 1); ++changed; } /* * "name/.." -> "" */ for (j = 0; j + 1 < sl.nstrings; ++j) { if (str_equal(sl.string[j], root)) continue; if (str_equal(sl.string[j], dotdot)) continue; if (!str_equal(sl.string[j + 1], dotdot)) continue; string_list_remove_nth(&sl, j); string_list_remove_nth(&sl, j); ++changed; --j; } /* * loop if anything changed, * bail if we can't find more to do */ if (!changed) break; } /* * reassemble the "cleaned" path */ s = wl2str_respect_empty(&sl, 0, sl.nstrings, "/", 1); string_list_destructor(&sl); return s; }
static int reserved(string_ty *s) { typedef struct table_ty table_ty; struct table_ty { char *name; int token; }; static table_ty table[] = { { "override", OVERRIDE }, { "include", INCLUDE2 }, { "-include", INCLUDE3 }, { ".include", INCLUDE }, { "vpath", VPATH }, { "VPATH", VPATH2 }, { "ifdef", IF }, { "ifndef", IF }, { "ifeq", IF }, { "ifneq", IF }, { "else", ELSE }, { "endif", ENDIF }, { "endef", ENDDEF }, { "define", DEFINE }, { "export", EXPORT }, { "unexport", UNEXPORT }, }; static symtab_ty *symtab; int *data; string_ty *name; char *cp; if (!symtab) { table_ty *tp; symtab = symtab_alloc(SIZEOF(table)); for (tp = table; tp < ENDOF(table); ++tp) { name = str_from_c(tp->name); symtab_assign(symtab, name, &tp->token); str_free(name); } } cp = strchr(s->str_text, '('); if (cp) { name = str_n_from_c(s->str_text, cp - s->str_text); data = symtab_query(symtab, name); str_free(name); } else data = symtab_query(symtab, s); if (data) return *data; return 0; }
static blob_list_ty * ifeq(blob_list_ty *blp, string_list_ty *ref) { blob_ty *arg; blob_ty *bp; blob_list_ty *result; string_ty *s; string_ty *s2; char *cp; size_t j; /* * allocate the result list */ trace(("ifeq()\n{\n")); result = blob_list_alloc(); /* * make sure we were given enough arguments */ if (blp->length < 2) { arg = blp->list[0]; blob_list_append ( result, blob_alloc(str_from_c("0"), arg->file_name, arg->line_number) ); trace(("}\n")); return result; } /* * turn the list of arguments into a single string */ arg = blp->list[1]; s = str_copy(blp->list[1]->text); for (j = 2; j < blp->length; ++j) { s2 = str_format("%s %s", s->str_text, blp->list[j]->text->str_text); str_free(s); s = s2; } bp = blob_alloc(s, arg->file_name, arg->line_number); /* * rename the variables * and reform to be a single string, again. */ variable_rename(bp, result, ref, VAREN_NO_QUOQUO); blob_free(bp); s = result->length ? str_copy(result->list[0]->text) : str_from_c("0"); for (j = 1; j < result->length; ++j) { s2 = str_format("%s %s", s->str_text, result->list[j]->text->str_text); str_free(s); s = s2; } blob_list_free(result); /* * construct the result */ result = blob_list_alloc(); switch (s->str_text[0]) { case '(': /* * ifeq (xxx,yyy) */ if (s->str_length < 3) goto useless; cp = strchr(s->str_text, ','); if (cp == 0 || s->str_text[s->str_length - 1] != ')') goto useless; blob_list_append ( result, blob_alloc(str_from_c("[in"), arg->file_name, arg->line_number) ); s2 = str_n_from_c(s->str_text + 1, cp - s->str_text - 1); if (s2->str_length == 0) s2 = str_from_c("\"\""); bp = blob_alloc(s2, arg->file_name, arg->line_number); blob_list_append(result, bp); s2 = str_n_from_c(cp + 1, s->str_text + s->str_length - cp - 2); if (s2->str_length == 0) s2 = str_from_c("\"\""); bp = blob_alloc(s2, arg->file_name, arg->line_number); blob_list_append(result, bp); blob_list_append ( result, blob_alloc(str_from_c("]"), arg->file_name, arg->line_number) ); break; case '\'': case '"': /* * ifeq "xxx" "yyy" */ if (s->str_length < 5) goto useless; cp = strchr(s->str_text + 1, s->str_text[0]); if ( !cp || cp[1] != ' ' || cp[2] != s->str_text[0] || s->str_text[s->str_length - 1] != s->str_text[0] ) goto useless; blob_list_append ( result, blob_alloc(str_from_c("[in"), arg->file_name, arg->line_number) ); s2 = str_n_from_c(s->str_text + 1, cp - s->str_text - 1); if (s2->str_length == 0) s2 = str_from_c("\"\""); bp = blob_alloc(s2, arg->file_name, arg->line_number); blob_list_append(result, bp); s2 = str_n_from_c(cp + 3, s->str_text + s->str_length - cp - 4); if (s2->str_length == 0) s2 = str_from_c("\"\""); bp = blob_alloc(s2, arg->file_name, arg->line_number); blob_list_append(result, bp); blob_list_append ( result, blob_alloc(str_from_c("]"), arg->file_name, arg->line_number) ); break; default: /* * We were given some useless thing, just rename the * variables and copy it through. */ useless: bp = blob_alloc(str_copy(s), arg->file_name, arg->line_number); blob_list_append(result, bp); break; } str_free(s); trace(("}\n")); return result; }
string_ty * str_from_c(const char *s) { return str_n_from_c(s, strlen(s)); }
static int interpret(string_list_ty *result, const string_list_ty *arg, const expr_position_ty *pp, const struct opcode_context_ty *ocp) { long start; long length; long end; size_t j; trace(("builtin::substr()\n{\n")); (void)ocp; if (arg->nstrings < 3) { sub_context_ty *scp; scp = sub_context_new(); sub_var_set_string(scp, "Name", arg->string[0]); error_with_position ( pp, scp, i18n("$name: requires two or more arguments") ); sub_context_delete(scp); trace(("return -1;\n")); trace(("}\n")); return -1; } if (!number(arg->string[1]->str_text, &start)) { sub_context_ty *scp; scp = sub_context_new(); sub_var_set_string(scp, "Name", arg->string[0]); sub_var_set(scp, "Number", "1"); error_with_position ( pp, scp, i18n("$name: argument $number: must be a positive decimal number") ); sub_context_delete(scp); trace(("return -1;\n")); trace(("}\n")); return -1; } --start; trace(("start = %ld;\n", start)); if (!number(arg->string[2]->str_text, &length)) { sub_context_ty *scp; scp = sub_context_new(); sub_var_set_string(scp, "Name", arg->string[0]); sub_var_set(scp, "Number", "2"); error_with_position ( pp, scp, i18n("$name: argument $number: must be a positive decimal number") ); sub_context_delete(scp); trace(("return -1;\n")); trace(("}\n")); return -1; } trace(("length = %ld;\n", length)); if (start < 0) { length += start; start = 0; trace(("length = %ld;\n", length)); } if (length < 0) { start = 0; length = 0; } end = start + length; for (j = 3; j < arg->nstrings; ++j) { string_ty *s; string_ty *s2; s = arg->string[j]; trace(("s = \"%s\";\n", s->str_text)); if (start >= (int)(s->str_length)) s2 = str_from_c(""); else if (end > (int)(s->str_length)) { s2 = str_n_from_c(s->str_text + start, s->str_length - start); } else s2 = str_n_from_c(s->str_text + start, length); trace(("s2 = \"%s\";\n", s2->str_text)); string_list_append(result, s2); str_free(s2); } trace(("return 0;\n")); trace(("}\n")); return 0; }