diff options
-rw-r--r-- | usr.bin/make/lowparse.c | 333 | ||||
-rw-r--r-- | usr.bin/make/lowparse.h | 21 | ||||
-rw-r--r-- | usr.bin/make/parse.c | 320 |
3 files changed, 337 insertions, 337 deletions
diff --git a/usr.bin/make/lowparse.c b/usr.bin/make/lowparse.c index 3c1faeee0dc..e265093ceab 100644 --- a/usr.bin/make/lowparse.c +++ b/usr.bin/make/lowparse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lowparse.c,v 1.1 2000/06/23 16:39:45 espie Exp $ */ +/* $OpenBSD: lowparse.c,v 1.2 2000/06/23 16:40:50 espie Exp $ */ /* low-level parsing functions. */ @@ -40,6 +40,20 @@ static LIST fileNames; /* file names to free at end */ #endif +/* Definitions for handling #include specifications */ +typedef struct IFile_ { + char *fname; /* name of file */ + unsigned long lineno; /* line number */ + FILE *F; /* open stream */ + char *str; /* read from char area */ + char *ptr; /* where we are */ + char *end; /* don't overdo it */ +} IFile; + +static IFile *current; + + + static LIST includes; /* stack of IFiles generated by * #includes */ @@ -48,6 +62,9 @@ static IFile *new_istring __P((char *, char *, unsigned long)); static void free_ifile __P((IFile *)); static void ParseVErrorInternal __P((char *, unsigned long, int, char *, va_list)); static int skiptoendofline __P((void)); +static int newline __P((void)); +#define ParseReadc() current->ptr < current->end ? *current->ptr++ : newline() +static void ParseUnreadc __P((char)); static int ParseSkipEmptyLines __P((Buffer)); static int fatals = 0; @@ -250,6 +267,320 @@ ParseUnreadc(c) *current->ptr = c; } +/* ParseSkipLine(): + * Grab the next line + */ +char * +ParseSkipLine(skip) + int skip; /* Skip lines that don't start with . */ +{ + char *line; + int c, lastc; + BUFFER buf; + + Buf_Init(&buf, MAKE_BSIZE); + + for (;;) { + Buf_Reset(&buf); + lastc = '\0'; + + while (((c = ParseReadc()) != '\n' || lastc == '\\') + && c != EOF) { + if (c == '\n') { + Buf_ReplaceLastChar(&buf, ' '); + current->lineno++; + + while ((c = ParseReadc()) == ' ' || c == '\t'); + + if (c == EOF) + break; + } + + Buf_AddChar(&buf, c); + lastc = c; + } + + line = Buf_Retrieve(&buf); + current->lineno++; + /* allow for non-newline terminated lines while skipping */ + if (line[0] == '.') + break; + + if (c == EOF) { + Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop"); + Buf_Destroy(&buf); + return NULL; + } + if (skip == 0) + break; + + } + + return line; +} + + +/*- + *--------------------------------------------------------------------- + * ParseReadLine -- + * Read an entire line from the input file. Called only by Parse_File. + * To facilitate escaped newlines and what have you, a character is + * buffered in 'lastc', which is '\0' when no characters have been + * read. When we break out of the loop, c holds the terminating + * character and lastc holds a character that should be added to + * the line (unless we don't read anything but a terminator). + * + * Results: + * A line w/o its newline + * + * Side Effects: + * Only those associated with reading a character + *--------------------------------------------------------------------- + */ +char * +ParseReadLine () +{ + BUFFER buf; /* Buffer for current line */ + register int c; /* the current character */ + register int lastc; /* The most-recent character */ + Boolean semiNL; /* treat semi-colons as newlines */ + Boolean ignDepOp; /* TRUE if should ignore dependency operators + * for the purposes of setting semiNL */ + Boolean ignComment; /* TRUE if should ignore comments (in a + * shell command */ + char *line; /* Result */ + char *ep; /* to strip trailing blanks */ + + semiNL = FALSE; + ignDepOp = FALSE; + ignComment = FALSE; + + /* + * Handle special-characters at the beginning of the line. Either a + * leading tab (shell command) or pound-sign (possible conditional) + * forces us to ignore comments and dependency operators and treat + * semi-colons as semi-colons (by leaving semiNL FALSE). This also + * discards completely blank lines. + */ + for (;;) { + c = ParseReadc(); + + if (c == '\t') { + ignComment = ignDepOp = TRUE; + break; + } else if (c == '\n') { + current->lineno++; + } else if (c == '#') { + ParseUnreadc(c); + break; + } else { + /* + * Anything else breaks out without doing anything + */ + break; + } + } + + if (c != EOF) { + lastc = c; + Buf_Init(&buf, MAKE_BSIZE); + + while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && + (c != EOF)) + { +test_char: + switch(c) { + case '\n': + /* + * Escaped newline: read characters until a non-space or an + * unescaped newline and replace them all by a single space. + * This is done by storing the space over the backslash and + * dropping through with the next nonspace. If it is a + * semi-colon and semiNL is TRUE, it will be recognized as a + * newline in the code below this... + */ + current->lineno++; + lastc = ' '; + while ((c = ParseReadc ()) == ' ' || c == '\t') { + continue; + } + if (c == EOF || c == '\n') { + goto line_read; + } else { + /* + * Check for comments, semiNL's, etc. -- easier than + * ParseUnreadc(c); continue; + */ + goto test_char; + } + /*NOTREACHED*/ + break; + + case ';': + /* + * Semi-colon: Need to see if it should be interpreted as a + * newline + */ + if (semiNL) { + /* + * To make sure the command that may be following this + * semi-colon begins with a tab, we push one back into the + * input stream. This will overwrite the semi-colon in the + * buffer. If there is no command following, this does no + * harm, since the newline remains in the buffer and the + * whole line is ignored. + */ + ParseUnreadc('\t'); + goto line_read; + } + break; + case '=': + if (!semiNL) { + /* + * Haven't seen a dependency operator before this, so this + * must be a variable assignment -- don't pay attention to + * dependency operators after this. + */ + ignDepOp = TRUE; + } else if (lastc == ':' || lastc == '!') { + /* + * Well, we've seen a dependency operator already, but it + * was the previous character, so this is really just an + * expanded variable assignment. Revert semi-colons to + * being just semi-colons again and ignore any more + * dependency operators. + * + * XXX: Note that a line like "foo : a:=b" will blow up, + * but who'd write a line like that anyway? + */ + ignDepOp = TRUE; semiNL = FALSE; + } + break; + case '#': + if (!ignComment) { + if ( +#if 0 + compatMake && +#endif + (lastc != '\\')) { + /* + * If the character is a hash mark and it isn't escaped + * (or we're being compatible), the thing is a comment. + * Skip to the end of the line. + */ + do { + c = ParseReadc(); + } while ((c != '\n') && (c != EOF)); + goto line_read; + } else { + /* + * Don't add the backslash. Just let the # get copied + * over. + */ + lastc = c; + continue; + } + } + break; + case ':': + case '!': + if (!ignDepOp && (c == ':' || c == '!')) { + /* + * A semi-colon is recognized as a newline only on + * dependency lines. Dependency lines are lines with a + * colon or an exclamation point. Ergo... + */ + semiNL = TRUE; + } + break; + } + /* + * Copy in the previous character and save this one in lastc. + */ + Buf_AddChar(&buf, lastc); + lastc = c; + + } + line_read: + current->lineno++; + + if (lastc != '\0') + Buf_AddChar(&buf, lastc); + line = Buf_Retrieve(&buf); + + /* + * Strip trailing blanks and tabs from the line. + * Do not strip a blank or tab that is preceeded by + * a '\' + */ + ep = line; + while (*ep) + ++ep; + while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { + if (ep > line + 1 && ep[-2] == '\\') + break; + --ep; + } + *ep = 0; + + if (line[0] == '.') { + /* + * 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 { + free (line); + line = ParseSkipLine(1); + } while (line && Cond_Eval(line) != COND_PARSE); + if (line == NULL) + break; + /*FALLTHRU*/ + case COND_PARSE: + free(line); + line = ParseReadLine(); + break; + case COND_INVALID: + { + For *loop; + + loop = For_Eval(line); + if (loop != NULL) { + Boolean ok; + + free(line); + do { + /* Find the matching endfor. */ + line = ParseSkipLine(0); + if (line == NULL) { + Parse_Error(PARSE_FATAL, + "Unexpected end of file in for loop.\n"); + return line; + } + ok = For_Accumulate(loop, line); + free(line); + } while (ok); + For_Run(loop); + line = ParseReadLine(); + } + break; + } + } + } + return (line); + + } else { + /* + * Hit end-of-file, so return a NULL line to indicate this. + */ + return((char *)NULL); + } +} + unsigned long Parse_Getlineno() { diff --git a/usr.bin/make/lowparse.h b/usr.bin/make/lowparse.h index 317de41774a..0ceb3939218 100644 --- a/usr.bin/make/lowparse.h +++ b/usr.bin/make/lowparse.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lowparse.h,v 1.1 2000/06/23 16:39:45 espie Exp $ */ +/* $OpenBSD: lowparse.h,v 1.2 2000/06/23 16:40:50 espie Exp $ */ /* * Copyright (c) 1999 Marc Espie. @@ -34,22 +34,7 @@ extern Boolean Parse_NextFile __P((void)); extern void LowParse_Init __P((void)); extern void LowParse_End __P((void)); #endif +extern char *ParseReadLine __P((void)); +extern char *ParseSkipLine __P((int)); extern void Finish_Errors __P((void)); -extern void ParseUnreadc __P((char)); - -/* Definitions for handling #include specifications */ -typedef struct IFile_ { - char *fname; /* name of file */ - unsigned long lineno; /* line number */ - FILE *F; /* open stream */ - char *str; /* read from char area */ - char *ptr; /* where we are */ - char *end; /* don't overdo it */ -} IFile; - -IFile *current; - -int newline __P((void)); -#define ParseReadc() current->ptr < current->end ? *current->ptr++ : newline() - #endif diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index bb9f0cdc3c7..a13b4e90935 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.c,v 1.50 2000/06/23 16:39:45 espie Exp $ */ +/* $OpenBSD: parse.c,v 1.51 2000/06/23 16:40:50 espie Exp $ */ /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ /* @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; #else -static char rcsid[] = "$OpenBSD: parse.c,v 1.50 2000/06/23 16:39:45 espie Exp $"; +static char rcsid[] = "$OpenBSD: parse.c,v 1.51 2000/06/23 16:40:50 espie Exp $"; #endif #endif /* not lint */ @@ -227,8 +227,6 @@ static void ParseDoInclude __P((char *)); static void ParseTraditionalInclude __P((char *)); #endif static void ParseLookupIncludeFile __P((char *, char *, Boolean)); -static char *ParseReadLine __P((void)); -static char *ParseSkipLine __P((int)); static void ParseFinishLine __P((void)); /*- @@ -1646,320 +1644,6 @@ ParseLookupIncludeFile(spec, endSpec, isSystem) } } -/* ParseSkipLine(): - * Grab the next line - */ -static char * -ParseSkipLine(skip) - int skip; /* Skip lines that don't start with . */ -{ - char *line; - int c, lastc; - BUFFER buf; - - Buf_Init(&buf, MAKE_BSIZE); - - for (;;) { - Buf_Reset(&buf); - lastc = '\0'; - - while (((c = ParseReadc()) != '\n' || lastc == '\\') - && c != EOF) { - if (c == '\n') { - Buf_ReplaceLastChar(&buf, ' '); - current->lineno++; - - while ((c = ParseReadc()) == ' ' || c == '\t'); - - if (c == EOF) - break; - } - - Buf_AddChar(&buf, c); - lastc = c; - } - - line = Buf_Retrieve(&buf); - current->lineno++; - /* allow for non-newline terminated lines while skipping */ - if (line[0] == '.') - break; - - if (c == EOF) { - Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop"); - Buf_Destroy(&buf); - return NULL; - } - if (skip == 0) - break; - - } - - return line; -} - - -/*- - *--------------------------------------------------------------------- - * ParseReadLine -- - * Read an entire line from the input file. Called only by Parse_File. - * To facilitate escaped newlines and what have you, a character is - * buffered in 'lastc', which is '\0' when no characters have been - * read. When we break out of the loop, c holds the terminating - * character and lastc holds a character that should be added to - * the line (unless we don't read anything but a terminator). - * - * Results: - * A line w/o its newline - * - * Side Effects: - * Only those associated with reading a character - *--------------------------------------------------------------------- - */ -static char * -ParseReadLine () -{ - BUFFER buf; /* Buffer for current line */ - register int c; /* the current character */ - register int lastc; /* The most-recent character */ - Boolean semiNL; /* treat semi-colons as newlines */ - Boolean ignDepOp; /* TRUE if should ignore dependency operators - * for the purposes of setting semiNL */ - Boolean ignComment; /* TRUE if should ignore comments (in a - * shell command */ - char *line; /* Result */ - char *ep; /* to strip trailing blanks */ - - semiNL = FALSE; - ignDepOp = FALSE; - ignComment = FALSE; - - /* - * Handle special-characters at the beginning of the line. Either a - * leading tab (shell command) or pound-sign (possible conditional) - * forces us to ignore comments and dependency operators and treat - * semi-colons as semi-colons (by leaving semiNL FALSE). This also - * discards completely blank lines. - */ - for (;;) { - c = ParseReadc(); - - if (c == '\t') { - ignComment = ignDepOp = TRUE; - break; - } else if (c == '\n') { - current->lineno++; - } else if (c == '#') { - ParseUnreadc(c); - break; - } else { - /* - * Anything else breaks out without doing anything - */ - break; - } - } - - if (c != EOF) { - lastc = c; - Buf_Init(&buf, MAKE_BSIZE); - - while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && - (c != EOF)) - { -test_char: - switch(c) { - case '\n': - /* - * Escaped newline: read characters until a non-space or an - * unescaped newline and replace them all by a single space. - * This is done by storing the space over the backslash and - * dropping through with the next nonspace. If it is a - * semi-colon and semiNL is TRUE, it will be recognized as a - * newline in the code below this... - */ - current->lineno++; - lastc = ' '; - while ((c = ParseReadc ()) == ' ' || c == '\t') { - continue; - } - if (c == EOF || c == '\n') { - goto line_read; - } else { - /* - * Check for comments, semiNL's, etc. -- easier than - * ParseUnreadc(c); continue; - */ - goto test_char; - } - /*NOTREACHED*/ - break; - - case ';': - /* - * Semi-colon: Need to see if it should be interpreted as a - * newline - */ - if (semiNL) { - /* - * To make sure the command that may be following this - * semi-colon begins with a tab, we push one back into the - * input stream. This will overwrite the semi-colon in the - * buffer. If there is no command following, this does no - * harm, since the newline remains in the buffer and the - * whole line is ignored. - */ - ParseUnreadc('\t'); - goto line_read; - } - break; - case '=': - if (!semiNL) { - /* - * Haven't seen a dependency operator before this, so this - * must be a variable assignment -- don't pay attention to - * dependency operators after this. - */ - ignDepOp = TRUE; - } else if (lastc == ':' || lastc == '!') { - /* - * Well, we've seen a dependency operator already, but it - * was the previous character, so this is really just an - * expanded variable assignment. Revert semi-colons to - * being just semi-colons again and ignore any more - * dependency operators. - * - * XXX: Note that a line like "foo : a:=b" will blow up, - * but who'd write a line like that anyway? - */ - ignDepOp = TRUE; semiNL = FALSE; - } - break; - case '#': - if (!ignComment) { - if ( -#if 0 - compatMake && -#endif - (lastc != '\\')) { - /* - * If the character is a hash mark and it isn't escaped - * (or we're being compatible), the thing is a comment. - * Skip to the end of the line. - */ - do { - c = ParseReadc(); - } while ((c != '\n') && (c != EOF)); - goto line_read; - } else { - /* - * Don't add the backslash. Just let the # get copied - * over. - */ - lastc = c; - continue; - } - } - break; - case ':': - case '!': - if (!ignDepOp && (c == ':' || c == '!')) { - /* - * A semi-colon is recognized as a newline only on - * dependency lines. Dependency lines are lines with a - * colon or an exclamation point. Ergo... - */ - semiNL = TRUE; - } - break; - } - /* - * Copy in the previous character and save this one in lastc. - */ - Buf_AddChar(&buf, lastc); - lastc = c; - - } - line_read: - current->lineno++; - - if (lastc != '\0') - Buf_AddChar(&buf, lastc); - line = Buf_Retrieve(&buf); - - /* - * Strip trailing blanks and tabs from the line. - * Do not strip a blank or tab that is preceeded by - * a '\' - */ - ep = line; - while (*ep) - ++ep; - while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { - if (ep > line + 1 && ep[-2] == '\\') - break; - --ep; - } - *ep = 0; - - if (line[0] == '.') { - /* - * 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 { - free (line); - line = ParseSkipLine(1); - } while (line && Cond_Eval(line) != COND_PARSE); - if (line == NULL) - break; - /*FALLTHRU*/ - case COND_PARSE: - free(line); - line = ParseReadLine(); - break; - case COND_INVALID: - { - For *loop; - - loop = For_Eval(line); - if (loop != NULL) { - Boolean ok; - - free(line); - do { - /* Find the matching endfor. */ - line = ParseSkipLine(0); - if (line == NULL) { - Parse_Error(PARSE_FATAL, - "Unexpected end of file in for loop.\n"); - return line; - } - ok = For_Accumulate(loop, line); - free(line); - } while (ok); - For_Run(loop); - line = ParseReadLine(); - } - break; - } - } - } - return (line); - - } else { - /* - * Hit end-of-file, so return a NULL line to indicate this. - */ - return((char *)NULL); - } -} - /*- *----------------------------------------------------------------------- * ParseFinishLine -- |