diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2007-07-30 10:03:12 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2007-07-30 10:03:12 +0000 |
commit | e7db4966f96a9de5cfd46d8c61c75ce28a7ea3dc (patch) | |
tree | 94c8f51b02b5fbbad6ea00ae500cb964428d603b | |
parent | efa0d3130461b35a2d6a7e220e7eb4221d97d4e4 (diff) |
introduce a Var_Substi to substitute on intervals.
Since we don't really know how to change Var_Subst and dependent functions,
we cheat, and copy the string to a buffer instead.
Clean-up the parser a bit: reorganize the include files lookup function:
introduce a resolve_include_filename function that figures out the full name
of the file, introduce a handle_include_file that does all the include file
handling, and rename the functions into handle_xxx_include, so that we
can remove most comments.
Rename ParseIsCond into handle_bsd_command, cut most of its code into
constituent functions.
Semantic changes:
- follow the rules that, if an optional construct does not parse correctly,
then it's not a real extension, and give the normal parser a chance to figure
it out. If the syntax checks out, semantic errors ARE real errors.
- allow variables to not be defined in include file names, no reason not to.
okay miod@
-rw-r--r-- | usr.bin/make/parse.c | 588 | ||||
-rw-r--r-- | usr.bin/make/var.c | 19 | ||||
-rw-r--r-- | usr.bin/make/var.h | 3 |
3 files changed, 295 insertions, 315 deletions
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index 100a9d9e38c..34ce909912e 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: parse.c,v 1.78 2007/07/30 09:51:53 espie Exp $ */ +/* $OpenBSD: parse.c,v 1.79 2007/07/30 10:03:11 espie Exp $ */ /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* @@ -215,16 +215,19 @@ static void add_target_nodes(const char *); static void ParseDoDependency(char *); static void ParseAddCmd(void *, void *); static void ParseHasCommands(void *); -static void ParseDoInclude(char *); -static void ParseDoPoison(char *); -static void ParseTraditionalInclude(char *); -static void ParseConditionalInclude(char *); -static void ParseLookupIncludeFile(char *, char *, bool, bool); +static bool handle_poison(const char *); +static bool handle_for_loop(Buffer, const char *); +static bool handle_undef(const char *); #define ParseReadLoopLine(linebuf) Parse_ReadUnparsedLine(linebuf, "for loop") static void ParseFinishDependency(void); -static bool ParseIsCond(Buffer, Buffer, char *); +static bool handle_bsd_command(Buffer, Buffer, const char *); static char *strip_comments(Buffer, const char *); -static char *find_include(const char *, bool); +static char *resolve_include_filename(const char *, bool); +static void handle_include_file(const char *, const char *, bool, bool); +static bool lookup_bsd_include(const char *); +static void lookup_sysv_style_include(const char *, const char *, bool); +static void lookup_sysv_include(const char *, const char *); +static void lookup_conditional_include(const char *, const char *); static void ParseDoCommands(const char *); @@ -1119,242 +1122,185 @@ ParseHasCommands(void *gnp) /* Node to examine */ } } -/*- - *----------------------------------------------------------------------- - * Parse_AddIncludeDir -- - * Add a directory to the path searched for included makefiles - * bracketed by double-quotes. Used by functions in main.c - *----------------------------------------------------------------------- - */ + + +/*** + *** Support for various include constructs + ***/ + + void -Parse_AddIncludeDir(const char *dir) /* The name of the directory to add */ +Parse_AddIncludeDir(const char *dir) { - Dir_AddDir(parseIncPath, dir); + Dir_AddDir(parseIncPath, dir); } -/*- - *--------------------------------------------------------------------- - * ParseDoInclude -- - * Push to another file. - * - * The input is the line minus the #include. A file spec is a string - * enclosed in <> or "". The former is looked for only in sysIncPath. - * The latter in . and the directories specified by -I command line - * options - * - * Side Effects: - * old parse context is pushed on the stack, new file becomes - * current context. - *--------------------------------------------------------------------- - */ -static void -ParseDoInclude(char *file)/* file specification */ +static char * +resolve_include_filename(const char *file, bool isSystem) { - char endc; /* the character which ends the file spec */ - char *cp; /* current position in file spec */ - bool isSystem; /* true if makefile is a system makefile */ - - /* Skip to delimiter character so we know where to look. */ - while (*file == ' ' || *file == '\t') - file++; + char *fullname; + + /* Look up system files on the system path first */ + if (isSystem) { + fullname = Dir_FindFileNoDot(file, sysIncPath); + if (fullname) + return fullname; + } - if (*file != '"' && *file != '<') { - Parse_Error(PARSE_FATAL, - ".include filename must be delimited by '\"' or '<'"); - return; - } + /* Handle non-system non-absolute files... */ + if (!isSystem && file[0] != '/') { + /* ... by looking first under the same directory as the + * current file */ + char *slash; + const char *fname; + + fname = Parse_Getfilename(); + + slash = strrchr(fname, '/'); + if (slash != NULL) { + char *newName; + + newName = Str_concati(fname, slash, file, + strchr(file, '\0'), '/'); + fullname = Dir_FindFile(newName, parseIncPath); + if (fullname == NULL) + fullname = Dir_FindFile(newName, dirSearchPath); + free(newName); + if (fullname) + return fullname; + } + } - /* Set the search path on which to find the include file based on the - * characters which bracket its name. Angle-brackets imply it's - * a system Makefile while double-quotes imply it's a user makefile */ - if (*file == '<') { - isSystem = true; - endc = '>'; - } else { - isSystem = false; - endc = '"'; - } + /* Now look first on the -I search path, then on the .PATH + * search path, if not found in a -I directory. + * XXX: Suffix specific? */ + fullname = Dir_FindFile(file, parseIncPath); + if (fullname) + return fullname; + fullname = Dir_FindFile(file, dirSearchPath); + if (fullname) + return fullname; - /* Skip to matching delimiter. */ - for (cp = ++file; *cp != endc; cp++) { - if (*cp == '\0') { - Parse_Error(PARSE_FATAL, - "Unclosed %cinclude filename. '%c' expected", - '.', endc); - return; - } - } - ParseLookupIncludeFile(file, cp, isSystem, true); + /* Still haven't found the makefile. Look for it on the system + * path as a last resort (if we haven't already). */ + if (isSystem) + return NULL; + else + return Dir_FindFile(file, sysIncPath); } -/*- - *--------------------------------------------------------------------- - * ParseTraditionalInclude -- - * Push to another file. - * - * The input is the line minus the "include". The file name is - * the string following the "include". - * - * Side Effects: - * old parse context is pushed on the stack, new file becomes - * current context. - * - * XXX May wish to support multiple files and wildcards ? - *--------------------------------------------------------------------- - */ static void -ParseTraditionalInclude(char *file) /* file specification */ +handle_include_file(const char *name, const char *ename, bool isSystem, + bool errIfNotFound) { - char *cp; /* current position in file spec */ - - /* Skip over whitespace. */ - while (isspace(*file)) - file++; - if (*file == '\0') { - Parse_Error(PARSE_FATAL, - "Filename missing from \"include\""); - return; - } - /* Skip to end of line or next whitespace. */ - for (cp = file; *cp != '\0' && !isspace(*cp);) - cp++; + char *file; + char *fullname; - ParseLookupIncludeFile(file, cp, true, true); -} + /* Substitute for any variables in the file name before trying to + * find the thing. */ + file = Var_Substi(name, ename, NULL, false); + + fullname = resolve_include_filename(file, isSystem); + if (fullname == NULL && errIfNotFound) + Parse_Error(PARSE_FATAL, "Could not find %s", file); + free(file); -/*- - *--------------------------------------------------------------------- - * ParseConditionalInclude -- - * May push to another file. - * - * No error if the file does not exist. - * See ParseTraditionalInclude otherwise. - *--------------------------------------------------------------------- - */ -static void -ParseConditionalInclude(char *file)/* file specification */ -{ - char *cp; /* current position in file spec */ - - /* Skip over whitespace. */ - while (isspace(*file)) - file++; - if (*file == '\0') { - Parse_Error(PARSE_FATAL, - "Filename missing from \"include\""); - return; - } - /* Skip to end of line or next whitespace. */ - for (cp = file; *cp != '\0' && !isspace(*cp);) - cp++; - ParseLookupIncludeFile(file, cp, true, false); + if (fullname != NULL) { + FILE *f; + + f = fopen(fullname, "r"); + if (f == NULL && errIfNotFound) + Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); + else + Parse_FromFile(fullname, f); + } } -/* helper function for ParseLookupIncludeFile */ -static char * -find_include(const char *file, bool isSystem) +/* .include <file> (system) or .include "file" (normal) */ +static bool +lookup_bsd_include(const char *file) { - char *fullname; - - /* Look up system files on the system path first */ - if (isSystem) { - fullname = Dir_FindFileNoDot(file, sysIncPath); - if (fullname) - return fullname; - } - - /* Handle non-system non-absolute files... */ - if (!isSystem && file[0] != '/') { - /* ... by first searching relative to the including file's - * location. We don't want to cd there, of course, so we - * just tack on the old file's leading path components - * and call Dir_FindFile to see if we can locate the beast. */ - char *slash; - const char *fname; - - fname = Parse_Getfilename(); - - slash = strrchr(fname, '/'); - if (slash != NULL) { - char *newName; - - newName = Str_concati(fname, slash, file, strchr(file, '\0'), '/'); - fullname = Dir_FindFile(newName, parseIncPath); - if (fullname == NULL) - fullname = Dir_FindFile(newName, dirSearchPath); - free(newName); - if (fullname) - return fullname; + char endc; + const char *efile; + bool isSystem; + + /* find starting delimiter */ + while (isspace(*file)) + file++; + + /* determine type of file */ + if (*file == '<') { + isSystem = true; + endc = '>'; + } else if (*file == '"') { + isSystem = false; + endc = '"'; + } else { + Parse_Error(PARSE_WARNING, + ".include filename must be delimited by '\"' or '<'"); + return false; } - } - /* Now look first on the -I search path, then on the .PATH - * search path, if not found in a -I directory. - * XXX: Suffix specific? */ - fullname = Dir_FindFile(file, parseIncPath); - if (fullname) - return fullname; - fullname = Dir_FindFile(file, dirSearchPath); - if (fullname) - return fullname; - - /* Still haven't found the makefile. Look for it on the system - * path as a last resort. */ - if (isSystem) - return NULL; - else - return Dir_FindFile(file, sysIncPath); + /* delimit file name between file and efile */ + for (efile = ++file; *efile != endc; efile++) { + if (*efile == '\0') { + Parse_Error(PARSE_WARNING, + "Unclosed .include filename. '%c' expected", endc); + return false; + } + } + handle_include_file(file, efile, isSystem, true); + return true; } -/* Common part to lookup and read an include file. */ + static void -ParseLookupIncludeFile(char *spec, char *endSpec, bool isSystem, - bool errIfNotFound) +lookup_sysv_style_include(const char *file, const char *directive, + bool errIfMissing) { - char *file; - char *fullname; - char endc; - - /* Substitute for any variables in the file name before trying to - * find the thing. */ - endc = *endSpec; - *endSpec = '\0'; - file = Var_Subst(spec, NULL, false); - *endSpec = endc; - - fullname = find_include(file, isSystem); - if (fullname == NULL && errIfNotFound) - Parse_Error(PARSE_FATAL, "Could not find %s", file); - + const char *efile; + + /* find beginning of name */ + while (isspace(*file)) + file++; + if (*file == '\0') { + Parse_Error(PARSE_FATAL, "Filename missing from \"%s\"", + directive); + return; + } + /* sys5 delimits file up to next blank character or end of line */ + for (efile = file; *efile != '\0' && !isspace(*efile);) + efile++; - free(file); + handle_include_file(file, efile, true, errIfMissing); +} - if (fullname != NULL) { - FILE *f; - f = fopen(fullname, "r"); - if (f == NULL && errIfNotFound) { - Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); - } else { - /* Once we find the absolute path to the file, we push the current - * stream to the includes stack, and start reading from the new - * file. We set up the file name to be its absolute name so that - * error messages are informative. */ - Parse_FromFile(fullname, f); - } - } +/* system V construct: include file */ +static void +lookup_sysv_include(const char *file, const char *directive) +{ + lookup_sysv_style_include(file, directive, true); } +/* sinclude file and -include file */ static void -ParseDoPoison(char *line) +lookup_conditional_include(const char *file, const char *directive) { - char *p = line; + lookup_sysv_style_include(file, directive, false); +} + + +static bool +handle_poison(const char *line) +{ + const char *p = line; int type = POISON_NORMAL; bool not = false; bool paren_to_match = false; - char *name, *ename; + const char *name, *ename; while (isspace(*p)) p++; @@ -1404,114 +1350,123 @@ ParseDoPoison(char *line) type = POISON_INVALID; break; } - if ((*p != '\0' && *p != '#') || type == POISON_INVALID) - Parse_Error(PARSE_FATAL, "Invalid syntax for .poison: %s", + if ((*p != '\0' && *p != '#') || type == POISON_INVALID) { + Parse_Error(PARSE_WARNING, "Invalid syntax for .poison: %s", line); - Var_MarkPoisoned(name, ename, type); + return false; + } else { + Var_MarkPoisoned(name, ename, type); + return true; + } } -/* Strip comments from the line. May return either a copy of the line, or - * the line itself. */ +/* Strip comments from the line. Build a copy in buffer if necessary, */ static char * strip_comments(Buffer copy, const char *line) { - const char *comment; - const char *p; - - comment = strchr(line, '#'); - assert(comment != line); - if (comment == NULL) - return (char *)line; - else { - Buf_Reset(copy); - - for (p = line; *p != '\0'; p++) { - if (*p == '\\') { - if (p[1] == '#') { - Buf_Addi(copy, line, p); - Buf_AddChar(copy, '#'); - line = p+2; + const char *comment; + const char *p; + + comment = strchr(line, '#'); + assert(comment != line); + if (comment == NULL) + return (char *)line; + else { + Buf_Reset(copy); + + for (p = line; *p != '\0'; p++) { + if (*p == '\\') { + if (p[1] == '#') { + Buf_Addi(copy, line, p); + Buf_AddChar(copy, '#'); + line = p+2; + } + if (p[1] != '\0') + p++; + } else if (*p == '#') + break; } - if (p[1] != '\0') - p++; - } else if (*p == '#') - break; + Buf_Addi(copy, line, p); + Buf_KillTrailingSpaces(copy); + return Buf_Retrieve(copy); } - Buf_Addi(copy, line, p); - Buf_KillTrailingSpaces(copy); - return Buf_Retrieve(copy); - } } static bool -ParseIsCond(Buffer linebuf, Buffer copy, char *line) +handle_for_loop(Buffer linebuf, const char *line) { - - char *stripped; - - while (isspace(*line)) - line++; - - /* The line might be a conditional. Ask the conditional module - * about it and act accordingly. */ - switch (Cond_Eval(line)) { - case COND_SKIP: - /* Skip to next conditional that evaluates to COND_PARSE. */ - do { - line = Parse_ReadNextConditionalLine(linebuf); - if (line != NULL) { - while (isspace(*line)) - line++; - stripped = strip_comments(copy, line); - } - } while (line != NULL && Cond_Eval(stripped) != COND_PARSE); - /* FALLTHROUGH */ - case COND_PARSE: - return true; - case COND_ISFOR: { For *loop; loop = For_Eval(line+3); if (loop != NULL) { - bool ok; - do { - /* Find the matching endfor. */ - line = ParseReadLoopLine(linebuf); - if (line == NULL) { - Parse_Error(PARSE_FATAL, - "Unexpected end of file in for loop.\n"); - return false; - } - ok = For_Accumulate(loop, line); - } while (ok); - For_Run(loop); - return true; - } - break; - } - case COND_ISINCLUDE: - ParseDoInclude(line + 7); - return true; - case COND_ISPOISON: - ParseDoPoison(line + 6); - return true; - case COND_ISUNDEF: { - char *cp; + bool ok; + do { + /* Find the matching endfor. */ + line = ParseReadLoopLine(linebuf); + if (line == NULL) { + Parse_Error(PARSE_FATAL, + "Unexpected end of file in for loop.\n"); + return false; + } + ok = For_Accumulate(loop, line); + } while (ok); + For_Run(loop); + return true; + } else + return false; +} + +static bool +handle_undef(const char *line) +{ + const char *eline; - line+=5; while (isspace(*line)) - line++; - for (cp = line; !isspace(*cp) && *cp != '\0';) - cp++; - Var_Deletei(line, cp); + line++; + for (eline = line; !isspace(*eline) && *eline != '\0';) + eline++; + Var_Deletei(line, eline); return true; - } - default: - break; - } +} + +static bool +handle_bsd_command(Buffer linebuf, Buffer copy, const char *line) +{ + char *stripped; - return false; + while (isspace(*line)) + line++; + + /* The line might be a conditional. Ask the conditional module + * about it and act accordingly. */ + switch (Cond_Eval(line)) { + case COND_SKIP: + /* Skip to next conditional that evaluates to COND_PARSE. */ + do { + line = Parse_ReadNextConditionalLine(linebuf); + if (line != NULL) { + while (isspace(*line)) + line++; + stripped = strip_comments(copy, line); + } + } while (line != NULL && Cond_Eval(stripped) != COND_PARSE); + /* FALLTHROUGH */ + case COND_PARSE: + return true; + case COND_ISFOR: + return handle_for_loop(linebuf, line); + case COND_ISINCLUDE: + return lookup_bsd_include(line + 7); + case COND_ISPOISON: + return handle_poison(line+6); + case COND_ISUNDEF: + return handle_undef(line + 5); + default: + break; + } + + return false; } /*- @@ -1575,20 +1530,25 @@ Parse_File( } else { char *stripped; stripped = strip_comments(©, line); - if (*stripped == '.' && ParseIsCond(&buf, ©, stripped+1)) - ; + if (*stripped == '.' && handle_bsd_command(&buf, ©, + stripped+1)) + ; else if (FEATURES(FEATURE_SYSVINCLUDE) && strncmp(stripped, "include", 7) == 0 && isspace(stripped[7]) && strchr(stripped, ':') == NULL) { /* It's an S3/S5-style "include". */ - ParseTraditionalInclude(stripped + 7); + lookup_sysv_include(stripped + 7, "include"); } else if (FEATURES(FEATURE_CONDINCLUDE) && - (*stripped == '-' || *stripped == 's') && - strncmp(stripped+1, "include", 7) == 0 && + strncmp(stripped, "sinclude", 8) == 0 && isspace(stripped[8]) && strchr(stripped, ':') == NULL) { - ParseConditionalInclude(stripped+8); + lookup_conditional_include(stripped+8, "sinclude"); + } else if (FEATURES(FEATURE_CONDINCLUDE) && + strncmp(stripped, "-include", 8) == 0 && + isspace(stripped[8]) && + strchr(stripped, ':') == NULL) { + lookup_conditional_include(stripped+8, "-include"); } else { char *dep; @@ -1654,15 +1614,15 @@ Parse_File( void Parse_Init(void) { - mainNode = NULL; - Static_Lst_Init(parseIncPath); - Static_Lst_Init(sysIncPath); - Array_Init(&gsources, SOURCES_SIZE); - Array_Init(>argets, TARGETS_SIZE); - - LowParse_Init(); + mainNode = NULL; + Static_Lst_Init(parseIncPath); + Static_Lst_Init(sysIncPath); + Array_Init(&gsources, SOURCES_SIZE); + Array_Init(>argets, TARGETS_SIZE); + + LowParse_Init(); #ifdef CLEANUP - Static_Lst_Init(&targCmds); + Static_Lst_Init(&targCmds); #endif } @@ -1670,10 +1630,10 @@ Parse_Init(void) void Parse_End(void) { - Lst_Destroy(&targCmds, (SimpleProc)free); - Lst_Destroy(sysIncPath, Dir_Destroy); - Lst_Destroy(parseIncPath, Dir_Destroy); - LowParse_End(); + Lst_Destroy(&targCmds, (SimpleProc)free); + Lst_Destroy(sysIncPath, Dir_Destroy); + Lst_Destroy(parseIncPath, Dir_Destroy); + LowParse_End(); } #endif diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c index 04a684e9845..715161df681 100644 --- a/usr.bin/make/var.c +++ b/usr.bin/make/var.c @@ -1,5 +1,5 @@ /* $OpenPackages$ */ -/* $OpenBSD: var.c,v 1.73 2007/07/30 09:51:53 espie Exp $ */ +/* $OpenBSD: var.c,v 1.74 2007/07/30 10:03:11 espie Exp $ */ /* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */ /* @@ -1104,6 +1104,22 @@ Var_Subst(const char *str, /* the string in which to substitute */ return Buf_Retrieve(&buf); } +static BUFFER subst_buffer; + +/* we would like to subst on intervals, but it's complicated, so we cheat + * by storing the interval in a static buffer. + */ +char * +Var_Substi(const char *str, const char *estr, SymTable *ctxt, bool undefErr) +{ + /* delimited string: no need to copy */ + if (estr == NULL || *estr == '\0') + return Var_Subst(str, ctxt, undefErr); + + Buf_Reset(&subst_buffer); + Buf_Addi(&subst_buffer, str, estr); + return Var_Subst(Buf_Retrieve(&subst_buffer), ctxt, undefErr); +} /*** *** Supplementary support for .for loops. @@ -1262,6 +1278,7 @@ Var_Init(void) Var_setCheckEnvFirst(false); VarModifiers_Init(); + Buf_Init(&subst_buffer, MAKE_BSIZE); } diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h index 0617f79b9b7..3fa22378f9e 100644 --- a/usr.bin/make/var.h +++ b/usr.bin/make/var.h @@ -121,6 +121,9 @@ extern bool Var_ParseBuffer(Buffer, const char *, SymTable *, * Emit a PARSE_FATAL error if undef_is_bad and an undef variable is * encountered. The result is always a copy that should be free. */ extern char *Var_Subst(const char *, SymTable *, bool); +/* subst = Var_Substi(str, estr, ctxt, undef_if_bad); + */ +extern char *Var_Substi(const char *, const char *, SymTable *, bool); /* For loop handling. |