diff options
author | Ron Yorston <rmy@pobox.com> | 2024-09-10 13:47:56 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-09-10 13:47:56 +0100 |
commit | 0b87e69888e52ce5ca797560124564efc794414c (patch) | |
tree | a4ccfbad0223339188c757f0e2f28752146277aa | |
parent | b4d811aa232df8c7416a14f38a2396b028c35ac9 (diff) | |
download | busybox-w32-0b87e69888e52ce5ca797560124564efc794414c.tar.gz busybox-w32-0b87e69888e52ce5ca797560124564efc794414c.tar.bz2 busybox-w32-0b87e69888e52ce5ca797560124564efc794414c.zip |
make: handling of leading whitespace in makefiles
Try to match how different makes handle leading whitespace in
makefiles. (Tested with GNU, BSD, Schily and UNIX Version 7
make.)
- Commands in rules must start with a tab. It's the law.
- BSD make doesn't allow any whitespace at the start of an include
line. Enforce this restriction in POSIX mode: 'the word include
... appears at the beginning of a line'. As an extension allow
arbitrary tabs or spaces.
- All implementations allow a space as the first character of a
macro definition or rule. Permit this in all cases.
- Only GNU make allows a tab as the first character of a macro
definition, but POSIX 2024 seems to permit it too: 'string1 is
defined as all characters from the first non-<blank> character to
the last non-<blank> character, inclusive'. Allow this in POSIX
2024 mode and as an extension.
- No implementation allows a tab as the first character of a rule.
Disallow this in all cases.
Adds 32-64 bytes.
(pdpmake GitHub issue 63)
-rw-r--r-- | miscutils/make.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/miscutils/make.c b/miscutils/make.c index b2edfdbb4..1e7b77ddb 100644 --- a/miscutils/make.c +++ b/miscutils/make.c | |||
@@ -1478,15 +1478,10 @@ expand_macros(const char *str, int except_dollar) | |||
1478 | /* | 1478 | /* |
1479 | * Process a non-command line | 1479 | * Process a non-command line |
1480 | */ | 1480 | */ |
1481 | static char * | 1481 | static void |
1482 | process_line(char *s) | 1482 | process_line(char *s) |
1483 | { | 1483 | { |
1484 | char *r, *t; | 1484 | char *t; |
1485 | |||
1486 | // Skip leading blanks | ||
1487 | while (isblank(*s)) | ||
1488 | s++; | ||
1489 | r = s; | ||
1490 | 1485 | ||
1491 | // Strip comment | 1486 | // Strip comment |
1492 | // don't treat '#' in macro expansion as a comment | 1487 | // don't treat '#' in macro expansion as a comment |
@@ -1519,8 +1514,6 @@ process_line(char *s) | |||
1519 | } | 1514 | } |
1520 | } | 1515 | } |
1521 | *t = '\0'; | 1516 | *t = '\0'; |
1522 | |||
1523 | return r; | ||
1524 | } | 1517 | } |
1525 | 1518 | ||
1526 | enum { | 1519 | enum { |
@@ -1605,8 +1598,8 @@ skip_line(const char *str1) | |||
1605 | int ret = cstate[clevel] & SKIP_LINE; | 1598 | int ret = cstate[clevel] & SKIP_LINE; |
1606 | int key; | 1599 | int key; |
1607 | 1600 | ||
1608 | copy = xstrdup(str1); | 1601 | q = copy = xstrdup(str1); |
1609 | q = process_line(copy); | 1602 | process_line(copy); |
1610 | if ((token = gettok(&q)) != NULL) { | 1603 | if ((token = gettok(&q)) != NULL) { |
1611 | switch (index_in_strings("else\0endif\0", token)) { | 1604 | switch (index_in_strings("else\0endif\0", token)) { |
1612 | case ENDIF: | 1605 | case ENDIF: |
@@ -2055,8 +2048,6 @@ input(FILE *fd, int ilevel) | |||
2055 | str1 = readline(fd, FALSE); | 2048 | str1 = readline(fd, FALSE); |
2056 | while (str1) { | 2049 | while (str1) { |
2057 | str2 = NULL; | 2050 | str2 = NULL; |
2058 | if (*str1 == '\t') // Command without target | ||
2059 | error("command not allowed here"); | ||
2060 | 2051 | ||
2061 | // Newlines and comments are handled differently in command lines | 2052 | // Newlines and comments are handled differently in command lines |
2062 | // and other types of line. Take a copy of the current line before | 2053 | // and other types of line. Take a copy of the current line before |
@@ -2066,9 +2057,13 @@ input(FILE *fd, int ilevel) | |||
2066 | // target: prereq; command | 2057 | // target: prereq; command |
2067 | // | 2058 | // |
2068 | copy = xstrdup(str1); | 2059 | copy = xstrdup(str1); |
2069 | str = process_line(str1); | 2060 | process_line(str1); |
2061 | str = str1; | ||
2070 | 2062 | ||
2071 | // Check for an include line | 2063 | // Check for an include line |
2064 | if (!posix) | ||
2065 | while (isblank(*str)) | ||
2066 | ++str; | ||
2072 | minus = !POSIX_2017 && *str == '-'; | 2067 | minus = !POSIX_2017 && *str == '-'; |
2073 | p = str + minus; | 2068 | p = str + minus; |
2074 | if (strncmp(p, "include", 7) == 0 && isblank(p[7])) { | 2069 | if (strncmp(p, "include", 7) == 0 && isblank(p[7])) { |
@@ -2117,6 +2112,11 @@ input(FILE *fd, int ilevel) | |||
2117 | } | 2112 | } |
2118 | 2113 | ||
2119 | // Check for a macro definition | 2114 | // Check for a macro definition |
2115 | str = str1; | ||
2116 | // POSIX 2024 seems to allow a tab as the first character of | ||
2117 | // a macro definition, though most implementations don't. | ||
2118 | if (POSIX_2017 && *str == '\t') | ||
2119 | error("command not allowed here"); | ||
2120 | if (find_char(str, '=') != NULL) { | 2120 | if (find_char(str, '=') != NULL) { |
2121 | int level = (useenv || fd == NULL) ? 4 : 3; | 2121 | int level = (useenv || fd == NULL) ? 4 : 3; |
2122 | // Use a copy of the line: we might need the original | 2122 | // Use a copy of the line: we might need the original |
@@ -2221,6 +2221,8 @@ input(FILE *fd, int ilevel) | |||
2221 | 2221 | ||
2222 | // If we get here it must be a target rule | 2222 | // If we get here it must be a target rule |
2223 | try_target: | 2223 | try_target: |
2224 | if (*str == '\t') // Command without target | ||
2225 | error("command not allowed here"); | ||
2224 | p = expanded = expand_macros(str, FALSE); | 2226 | p = expanded = expand_macros(str, FALSE); |
2225 | 2227 | ||
2226 | // Look for colon separator | 2228 | // Look for colon separator |