diff --git a/commands.c b/commands.c index 6a9df7c2..4303b86d 100644 --- a/commands.c +++ b/commands.c @@ -414,7 +414,7 @@ chop_commands (struct commands *cmds) unsigned char flags = 0; const char *p = lines[idx]; - while (isblank (*p) || *p == '-' || *p == '@' || *p == '+') + while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+') switch (*(p++)) { case '+': @@ -451,7 +451,7 @@ execute_file_commands (struct file *file) the commands are nothing but whitespace. */ for (p = file->cmds->commands; *p != '\0'; ++p) - if (!isspace ((unsigned char)*p) && *p != '-' && *p != '@') + if (!ISSPACE (*p) && *p != '-' && *p != '@' && *p != '+') break; if (*p == '\0') { diff --git a/expand.c b/expand.c index bb210189..de832b37 100644 --- a/expand.c +++ b/expand.c @@ -384,7 +384,7 @@ variable_expand_string (char *line, const char *string, long length) break; default: - if (isblank ((unsigned char)p[-1])) + if (ISSPACE (p[-1])) break; /* A $ followed by a random char is a variable reference: diff --git a/function.c b/function.c index a80f194f..28015981 100644 --- a/function.c +++ b/function.c @@ -115,8 +115,8 @@ subst_expand (char *o, const char *text, const char *subst, const char *replace, /* If we're substituting only by fully matched words, or only at the ends of words, check that this case qualifies. */ if (by_word - && ((p > text && !isblank ((unsigned char)p[-1])) - || ! STOP_SET (p[slen], MAP_BLANK|MAP_NUL))) + && ((p > text && !ISSPACE (p[-1])) + || ! STOP_SET (p[slen], MAP_SPACE|MAP_NUL))) /* Struck out. Output the rest of the string that is no longer to be replaced. */ o = variable_buffer_output (o, subst, slen); @@ -754,9 +754,9 @@ func_words (char *o, char **argv, const char *funcname UNUSED) char * strip_whitespace (const char **begpp, const char **endpp) { - while (*begpp <= *endpp && isspace ((unsigned char)**begpp)) + while (*begpp <= *endpp && ISSPACE (**begpp)) (*begpp) ++; - while (*endpp >= *begpp && isspace ((unsigned char)**endpp)) + while (*endpp >= *begpp && ISSPACE (**endpp)) (*endpp) --; return (char *)*begpp; } @@ -869,8 +869,12 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED) unsigned int len; struct variable *var; + /* Clean up the variable name by removing whitespace. */ + char *vp = next_token (varname); + end_of_token (vp)[0] = '\0'; + push_new_variable_scope (); - var = define_variable (varname, strlen (varname), "", o_automatic, 0); + var = define_variable (vp, strlen (vp), "", o_automatic, 0); /* loop through LIST, put the value in VAR and expand BODY */ while ((p = find_next_token (&list_iterator, &len)) != 0) @@ -1080,10 +1084,9 @@ func_strip (char *o, char **argv, const char *funcname UNUSED) int i=0; const char *word_start; - while (isspace ((unsigned char)*p)) - ++p; + NEXT_TOKEN (p); word_start = p; - for (i=0; *p != '\0' && !isspace ((unsigned char)*p); ++p, ++i) + for (i=0; *p != '\0' && !ISSPACE (*p); ++p, ++i) {} if (!i) break; @@ -1614,8 +1617,7 @@ msdos_openpipe (int* pipedes, int *pidp, char *text) extern int dos_command_running, dos_status; /* Make sure not to bother processing an empty line. */ - while (isblank ((unsigned char)*text)) - ++text; + NEXT_TOKEN (text); if (*text == '\0') return 0; @@ -2001,8 +2003,7 @@ func_not (char *o, char **argv, char *funcname UNUSED) { const char *s = argv[0]; int result = 0; - while (isspace ((unsigned char)*s)) - s++; + NEXT_TOKEN (s); result = ! (*s); o = variable_buffer_output (o, result ? "1" : "", result); return o; @@ -2206,7 +2207,7 @@ func_file (char *o, char **argv, const char *funcname UNUSED) mode = "a"; ++fn; } - fn = next_token (fn); + NEXT_TOKEN (fn); if (fn[0] == '\0') O (fatal, *expanding_var, _("file: missing filename")); @@ -2231,7 +2232,8 @@ func_file (char *o, char **argv, const char *funcname UNUSED) char *preo = o; FILE *fp; - fn = next_token (++fn); + ++fn; + NEXT_TOKEN (fn); if (fn[0] == '\0') O (fatal, *expanding_var, _("file: missing filename")); @@ -2441,7 +2443,8 @@ handle_function (char **op, const char **stringp) /* We found a builtin function. Find the beginning of its arguments (skip whitespace after the name). */ - beg = next_token (beg + entry_p->len); + beg += entry_p->len; + NEXT_TOKEN (beg); /* Find the end of the function invocation, counting nested use of whichever kind of parens we use. Since we're looking, count commas @@ -2541,7 +2544,6 @@ func_call (char *o, char **argv, const char *funcname UNUSED) { static int max_args = 0; char *fname; - char *cp; char *body; int flen; int i; @@ -2549,16 +2551,9 @@ func_call (char *o, char **argv, const char *funcname UNUSED) const struct function_table_entry *entry_p; struct variable *v; - /* There is no way to define a variable with a space in the name, so strip - leading and trailing whitespace as a favor to the user. */ - fname = argv[0]; - while (isspace ((unsigned char)*fname)) - ++fname; - - cp = fname + strlen (fname) - 1; - while (cp > fname && isspace ((unsigned char)*cp)) - --cp; - cp[1] = '\0'; + /* Clean up the name of the variable to be invoked. */ + fname = next_token (argv[0]); + end_of_token (fname)[0] = '\0'; /* Calling nothing is a no-op */ if (*fname == '\0') diff --git a/implicit.c b/implicit.c index aa33b833..ed49bd16 100644 --- a/implicit.c +++ b/implicit.c @@ -72,8 +72,7 @@ get_next_word (const char *buffer, unsigned int *length) char c; /* Skip any leading whitespace. */ - while (isblank ((unsigned char)*p)) - ++p; + NEXT_TOKEN (p); beg = p; c = *(p++); diff --git a/job.c b/job.c index 6fa9e8a8..512240fd 100644 --- a/job.c +++ b/job.c @@ -1099,7 +1099,8 @@ start_job_command (struct child *child) flags |= COMMANDS_RECURSE; else if (*p == '-') child->noerror = 1; - else if (!isblank ((unsigned char)*p)) + /* Don't skip newlines. */ + else if (!ISBLANK (*p)) break; ++p; } @@ -1137,7 +1138,7 @@ start_job_command (struct child *child) /* Skip any leading whitespace */ while (*p) { - if (!isspace(*p)) + if (!ISSPACE (*p)) { if (*p != '\\') break; @@ -1712,14 +1713,13 @@ new_job (struct file *file) *out++ = *in++; else { - /* Skip the backslash, newline and - any following whitespace. */ - in = next_token (in + 2); + /* Skip the backslash, newline, and whitespace. */ + in += 2; + NEXT_TOKEN (in); /* Discard any preceding whitespace that has already been written to the output. */ - while (out > outref - && isblank ((unsigned char)out[-1])) + while (out > outref && ISBLANK (out[-1])) --out; /* Replace it all with a single space. */ @@ -2553,8 +2553,8 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, if (restp != NULL) *restp = NULL; - /* Make sure not to bother processing an empty line. */ - while (isblank ((unsigned char)*line)) + /* Make sure not to bother processing an empty line but stop at newline. */ + while (ISBLANK (*line)) ++line; if (*line == '\0') return 0; @@ -2729,15 +2729,16 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, /* Throw out the backslash and newline. */ ++p; - /* If there's nothing in this argument yet, skip any - whitespace before the start of the next word. */ + /* At the beginning of the argument, skip any whitespace other + than newline before the start of the next word. */ if (ap == new_argv[i]) - p = next_token (p + 1) - 1; + while (ISBLANK (p[1])) + ++p; } #ifdef WINDOWS32 /* Backslash before whitespace is not special if our shell is not Unixy. */ - else if (isspace (p[1]) && !unixy_shell) + else if (ISSPACE (p[1]) && !unixy_shell) { *ap++ = *p; break; @@ -2764,7 +2765,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, else #endif if (p[1] != '\\' && p[1] != '\'' - && !isspace ((unsigned char)p[1]) + && !ISSPACE (p[1]) && strchr (sh_chars_sh, p[1]) == 0) /* back up one notch, to copy the backslash */ --p; @@ -2828,8 +2829,9 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, } } - /* Ignore multiple whitespace chars. */ - p = next_token (p) - 1; + /* Skip whitespace chars, but not newlines. */ + while (ISBLANK (p[1])) + ++p; break; default: @@ -2922,8 +2924,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, */ /* Make sure not to bother processing an empty line. */ - while (isspace ((unsigned char)*line)) - ++line; + NEXT_TOKEN (line); if (*line == '\0') return 0; #endif /* WINDOWS32 */ @@ -2983,9 +2984,9 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, { int esc = 0; - /* This is the start of a new recipe line. - Skip whitespace and prefix characters. */ - while (isblank (*f) || *f == '-' || *f == '@' || *f == '+') + /* This is the start of a new recipe line. Skip whitespace + and prefix characters but not newlines. */ + while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') ++f; /* Copy until we get to the next logical recipe line. */ @@ -3035,21 +3036,21 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, [@+-]: they're meaningless in .ONESHELL mode. */ while (*f != '\0') { - /* This is the start of a new recipe line. - Skip whitespace and prefix characters. */ - while (isblank (*f) || *f == '-' || *f == '@' || *f == '+') + /* This is the start of a new recipe line. Skip whitespace + and prefix characters but not newlines. */ + while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') ++f; /* Copy until we get to the next logical recipe line. */ while (*f != '\0') { - /* Remove the escaped newlines in the command, and - the whitespace that follows them. Windows - shells cannot handle escaped newlines. */ + /* Remove the escaped newlines in the command, and the + blanks that follow them. Windows shells cannot handle + escaped newlines. */ if (*f == '\\' && f[1] == '\n') { f += 2; - while (isblank (*f)) + while (ISBLANK (*f)) ++f; } *(t++) = *(f++); @@ -3161,7 +3162,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell, /* DOS shells don't know about backslash-escaping. */ if (unixy_shell && !batch_mode_shell && (*p == '\\' || *p == '\'' || *p == '"' - || isspace ((unsigned char)*p) + || ISSPACE (*p) || strchr (sh_chars, *p) != 0)) *ap++ = '\\'; #ifdef __MSDOS__ @@ -3366,13 +3367,11 @@ construct_command_argv (char *line, char **restp, struct file *file, cptr = line; for (;;) { - while ((*cptr != 0) - && (isspace ((unsigned char)*cptr))) + while ((*cptr != 0) && (ISSPACE (*cptr))) cptr++; if (*cptr == 0) break; - while ((*cptr != 0) - && (!isspace ((unsigned char)*cptr))) + while ((*cptr != 0) && (!ISSPACE (*cptr))) cptr++; argc++; } @@ -3385,15 +3384,13 @@ construct_command_argv (char *line, char **restp, struct file *file, argc = 0; for (;;) { - while ((*cptr != 0) - && (isspace ((unsigned char)*cptr))) + while ((*cptr != 0) && (ISSPACE (*cptr))) cptr++; if (*cptr == 0) break; DB (DB_JOBS, ("argv[%d] = [%s]\n", argc, cptr)); argv[argc++] = cptr; - while ((*cptr != 0) - && (!isspace ((unsigned char)*cptr))) + while ((*cptr != 0) && (!ISSPACE (*cptr))) cptr++; if (*cptr != 0) *cptr++ = 0; diff --git a/main.c b/main.c index 22af6011..6239702c 100644 --- a/main.c +++ b/main.c @@ -661,21 +661,22 @@ initialize_stopchar_map () stopchar_map[(int)'/'] = MAP_DIRSEP; #if defined(VMS) - stopchar_map[(int)':'] = MAP_COLON | MAP_DIRSEP; - stopchar_map[(int)']'] = MAP_DIRSEP; - stopchar_map[(int)'>'] = MAP_DIRSEP; + stopchar_map[(int)':'] |= MAP_DIRSEP; + stopchar_map[(int)']'] |= MAP_DIRSEP; + stopchar_map[(int)'>'] |= MAP_DIRSEP; #elif defined(HAVE_DOS_PATHS) - stopchar_map[(int)'\\'] = MAP_DIRSEP; + stopchar_map[(int)'\\'] |= MAP_DIRSEP; #endif for (i = 1; i <= UCHAR_MAX; ++i) { - if (isblank(i)) - stopchar_map[i] = MAP_BLANK; - if (isspace(i)) - stopchar_map[i] |= MAP_SPACE; - if (isalnum(i)) - stopchar_map[i] = MAP_USERFUNC; + if (isblank (i)) + stopchar_map[i] |= MAP_BLANK; + else if (isspace (i)) + /* Don't mark blank characters as newline characters. */ + stopchar_map[i] |= MAP_NEWLINE; + else if (isalnum (i)) + stopchar_map[i] |= MAP_USERFUNC; } } @@ -2985,7 +2986,7 @@ decode_env_switches (const char *envar, unsigned int len) value = variable_expand (varref); /* Skip whitespace, and check for an empty value. */ - value = next_token (value); + NEXT_TOKEN (value); len = strlen (value); if (len == 0) return; @@ -3008,14 +3009,14 @@ decode_env_switches (const char *envar, unsigned int len) { if (*value == '\\' && value[1] != '\0') ++value; /* Skip the backslash. */ - else if (isblank ((unsigned char)*value)) + else if (ISBLANK (*value)) { /* End of the word. */ *p++ = '\0'; argv[++argc] = p; do ++value; - while (isblank ((unsigned char)*value)); + while (ISBLANK (*value)); continue; } *p++ = *value++; @@ -3046,7 +3047,7 @@ quote_for_env (char *out, const char *in) { if (*in == '$') *out++ = '$'; - else if (isblank ((unsigned char)*in) || *in == '\\') + else if (ISBLANK (*in) || *in == '\\') *out++ = '\\'; *out++ = *in++; } diff --git a/makeint.h b/makeint.h index 30bfe609..ff6df003 100644 --- a/makeint.h +++ b/makeint.h @@ -95,10 +95,6 @@ char *alloca (); extern int errno; #endif -#ifndef isblank -# define isblank(c) ((c) == ' ' || (c) == '\t') -#endif - #ifdef __VMS /* In strict ANSI mode, VMS compilers should not be defining the VMS macro. Define it here instead of a bulk edit for the correct code. @@ -348,21 +344,6 @@ char *strsignal (int signum); #define N_(msgid) gettext_noop (msgid) #define S_(msg1,msg2,num) ngettext (msg1,msg2,num) -/* Handle other OSs. - To overcome an issue parsing paths in a DOS/Windows environment when - built in a unix based environment, override the PATH_SEPARATOR_CHAR - definition unless being built for Cygwin. */ -#if defined(HAVE_DOS_PATHS) && !defined(__CYGWIN__) -# undef PATH_SEPARATOR_CHAR -# define PATH_SEPARATOR_CHAR ';' -#elif !defined(PATH_SEPARATOR_CHAR) -# if defined (VMS) -# define PATH_SEPARATOR_CHAR (vms_comma_separator ? ',' : ':') -# else -# define PATH_SEPARATOR_CHAR ':' -# endif -#endif - /* This is needed for getcwd() and chdir(), on some W32 systems. */ #if defined(HAVE_DIRECT_H) # include @@ -398,7 +379,7 @@ extern int unixy_shell; # endif /* Include only the minimal stuff from windows.h. */ -#define WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN #endif /* WINDOWS32 */ #define ANY_SET(_v,_m) (((_v)&(_m)) != 0) @@ -406,7 +387,7 @@ extern int unixy_shell; #define MAP_NUL 0x0001 #define MAP_BLANK 0x0002 -#define MAP_SPACE 0x0004 +#define MAP_NEWLINE 0x0004 #define MAP_COMMENT 0x0008 #define MAP_SEMI 0x0010 #define MAP_EQUALS 0x0020 @@ -429,7 +410,40 @@ extern int unixy_shell; # define MAP_VMSCOMMA 0x0000 #endif -#define STOP_SET(_v,_m) ANY_SET (stopchar_map[(unsigned char)(_v)],(_m)) +#define MAP_SPACE (MAP_BLANK|MAP_NEWLINE) + +/* Handle other OSs. + To overcome an issue parsing paths in a DOS/Windows environment when + built in a unix based environment, override the PATH_SEPARATOR_CHAR + definition unless being built for Cygwin. */ +#if defined(HAVE_DOS_PATHS) && !defined(__CYGWIN__) +# undef PATH_SEPARATOR_CHAR +# define PATH_SEPARATOR_CHAR ';' +# define MAP_PATHSEP MAP_SEMI +#elif !defined(PATH_SEPARATOR_CHAR) +# if defined (VMS) +# define PATH_SEPARATOR_CHAR (vms_comma_separator ? ',' : ':') +# define MAP_PATHSEP (vms_comma_separator ? MAP_COMMA : MAP_SEMI) +# else +# define PATH_SEPARATOR_CHAR ':' +# define MAP_PATHSEP MAP_COLON +# endif +#elif PATH_SEPARATOR_CHAR == ':' +# define MAP_PATHSEP MAP_COLON +#elif PATH_SEPARATOR_CHAR == ';' +# define MAP_PATHSEP MAP_SEMI +#elif PATH_SEPARATOR_CHAR == ',' +# define MAP_PATHSEP MAP_COMMA +#else +# error "Unknown PATH_SEPARATOR_CHAR" +#endif + +#define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m)) + +#define ISBLANK(c) STOP_SET((c),MAP_BLANK) +#define ISSPACE(c) STOP_SET((c),MAP_SPACE) +#define NEXT_TOKEN(s) while (ISSPACE (*(s))) ++(s) +#define END_OF_TOKEN(s) while (! STOP_SET (*(s), MAP_SPACE|MAP_NUL)) ++(s) #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) # define SET_STACK_SIZE diff --git a/misc.c b/misc.c index de8a1b19..f2fa24f1 100644 --- a/misc.c +++ b/misc.c @@ -91,12 +91,13 @@ collapse_continuations (char *line) { /* Backslash/newline handling: In traditional GNU make all trailing whitespace, consecutive - backslash/newlines, and any leading whitespace on the next line - is reduced to a single space. + backslash/newlines, and any leading non-newline whitespace on the + next line is reduced to a single space. In POSIX, each backslash/newline and is replaced by a space. */ - in = next_token (in); + while (ISBLANK (*in)) + ++in; if (! posix_pedantic) - while (out > line && isblank ((unsigned char)out[-1])) + while (out > line && ISBLANK (out[-1])) --out; *out++ = ' '; } @@ -314,8 +315,7 @@ lindex (const char *s, const char *limit, int c) char * end_of_token (const char *s) { - while (! STOP_SET (*s, MAP_BLANK|MAP_NUL)) - ++s; + END_OF_TOKEN (s); return (char *)s; } @@ -324,8 +324,7 @@ end_of_token (const char *s) char * next_token (const char *s) { - while (isblank ((unsigned char)*s)) - ++s; + NEXT_TOKEN (s); return (char *)s; } diff --git a/read.c b/read.c index bcd6c243..08739a54 100644 --- a/read.c +++ b/read.c @@ -511,7 +511,7 @@ parse_var_assignment (const char *line, struct vmodifiers *vmod) memset (vmod, '\0', sizeof (*vmod)); /* Find the start of the next token. If there isn't one we're done. */ - line = next_token (line); + NEXT_TOKEN (line); if (*line == '\0') return (char *)line; @@ -720,8 +720,7 @@ eval (struct ebuffer *ebuf, int set_default) /* Get rid if starting space (including formfeed, vtab, etc.) */ p = collapsed; - while (isspace ((unsigned char)*p)) - ++p; + NEXT_TOKEN (p); /* See if this is a variable assignment. We need to do this early, to allow variables with names like 'ifdef', 'export', 'private', etc. */ @@ -769,7 +768,7 @@ eval (struct ebuffer *ebuf, int set_default) p2 = end_of_token (p); wlen = p2 - p; - p2 = next_token (p2); + NEXT_TOKEN (p2); /* If we're in an ignored define, skip this line (but maybe get out). */ if (in_ignored_define) @@ -1242,8 +1241,7 @@ eval (struct ebuffer *ebuf, int set_default) The rule is that it's only a target, if there are TWO :'s OR a space around the :. */ - if (p && !(isspace ((unsigned char)p[1]) || !p[1] - || isspace ((unsigned char)p[-1]))) + if (p && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1]))) p = 0; #endif #ifdef HAVE_DOS_PATHS @@ -1436,7 +1434,7 @@ do_undefine (char *name, enum variable_origin origin, struct ebuffer *ebuf) if (*name == '\0') O (fatal, &ebuf->floc, _("empty variable name")); p = name + strlen (name) - 1; - while (p > name && isblank ((unsigned char)*p)) + while (p > name && ISBLANK (*p)) --p; p[1] = '\0'; @@ -1481,7 +1479,7 @@ do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf) if (name[0] == '\0') O (fatal, &defstart, _("empty variable name")); p = name + strlen (name) - 1; - while (p > name && isblank ((unsigned char)*p)) + while (p > name && ISBLANK (*p)) --p; p[1] = '\0'; @@ -1509,13 +1507,13 @@ do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf) len = strlen (p); /* If this is another 'define', increment the level count. */ - if ((len == 6 || (len > 6 && isblank ((unsigned char)p[6]))) + if ((len == 6 || (len > 6 && ISBLANK (p[6]))) && strneq (p, "define", 6)) ++nlevels; /* If this is an 'endef', decrement the count. If it's now 0, we've found the last one. */ - else if ((len == 5 || (len > 5 && isblank ((unsigned char)p[5]))) + else if ((len == 5 || (len > 5 && ISBLANK (p[5]))) && strneq (p, "endef", 5)) { p += 5; @@ -1591,7 +1589,8 @@ conditional_line (char *line, int len, const gmk_floc *flocp) return -2; /* Found one: skip past it and any whitespace after it. */ - line = next_token (line + len); + line += len; + NEXT_TOKEN (line); #define EXTRATEXT() OS (error, flocp, _("extraneous text after '%s' directive"), cmdname) #define EXTRACMD() OS (fatal, flocp, _("extraneous '%s'"), cmdname) @@ -1712,7 +1711,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp) /* Make sure there's only one variable name to test. */ p = end_of_token (var); i = p - var; - p = next_token (p); + NEXT_TOKEN (p); if (*p != '\0') return -1; @@ -1758,7 +1757,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp) { /* Strip blanks after the first string. */ char *p = line++; - while (isblank ((unsigned char)p[-1])) + while (ISBLANK (p[-1])) --p; *p = '\0'; } @@ -1774,7 +1773,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp) if (termin != ',') /* Find the start of the second string. */ - line = next_token (line); + NEXT_TOKEN (line); termin = termin == ',' ? ')' : *line; if (termin != ')' && termin != '"' && termin != '\'') @@ -1809,8 +1808,8 @@ conditional_line (char *line, int len, const gmk_floc *flocp) if (*line == '\0') return -1; - *line = '\0'; - line = next_token (++line); + *(line++) = '\0'; + NEXT_TOKEN (line); if (*line != '\0') EXTRATEXT (); @@ -2641,7 +2640,7 @@ get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length) char c; /* Skip any leading whitespace. */ - while (isblank ((unsigned char)*p)) + while (ISBLANK (*p)) ++p; beg = p; @@ -3076,7 +3075,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap, int i; /* Skip whitespace; at the end of the string or STOPCHAR we're done. */ - p = next_token (p); + NEXT_TOKEN (p); if (STOP_SET (*p, stopmap)) break; @@ -3091,8 +3090,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap, #endif #ifdef _AMIGA if (p && STOP_SET (*p, stopmap & MAP_COLON) - && !(isspace ((unsigned char)p[1]) || !p[1] - || isspace ((unsigned char)p[-1]))) + && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1]))) p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK); #endif #ifdef HAVE_DOS_PATHS @@ -3101,7 +3099,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap, Note that tokens separated by spaces should be treated as separate tokens since make doesn't allow path names with spaces */ if (stopmap | MAP_COLON) - while (p != 0 && !isspace ((unsigned char)*p) && + while (p != 0 && !ISSPACE (*p) && (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1])) p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK); #endif @@ -3196,7 +3194,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap, do { const char *o = e; - e = next_token (e); + NEXT_TOKEN (e); /* Find the end of this word. We don't want to unquote and we don't care about quoting since we're looking for the last char in the word. */ diff --git a/tests/scripts/functions/call b/tests/scripts/functions/call index 9db9da71..dc1a6233 100644 --- a/tests/scripts/functions/call +++ b/tests/scripts/functions/call @@ -4,11 +4,7 @@ $description = "Test the call function.\n"; $details = "Try various uses of call and ensure they all give the correct results.\n"; -open(MAKEFILE, "> $makefile"); - -# The Contents of the MAKEFILE ... - -print MAKEFILE <<'EOMAKE'; +run_make_test(q! # Simple, just reverse two things # reverse = $2 $1 @@ -48,35 +44,22 @@ all: ; @echo '$(call reverse,bar,foo)'; \ echo '$(call my-foreach,a,,,)'; \ echo '$(call my-if,a,b,c)'; \ echo '$(call two,bar,baz)'; \ - echo '$(call tclose,foo)' + echo '$(call tclose,foo)'; +!, + "", "foo bar\ndefault file file\nb d f\n\n\nb\nbar foo baz\nfoo bar baz blarp quux \n"); - - -EOMAKE - -# These won't work until/unless PR/1527 is resolved. -# echo '$(call my-foreach,a,x y z,$(a)$(a))'; \ -# echo '$(call my-if,,$(warning don't print this),ok)' +# These won't work because call expands all its arguments first, before +# passing them on, then marks them as resolved/simple, so they're not +# expanded again by the function. # -# $answer = "xx yy zz\nok\n"; - -# END of Contents of MAKEFILE - -close(MAKEFILE); - -&run_make_with_options($makefile, "", &get_logfile); -$answer = "foo bar\ndefault file file\nb d f\n\n\nb\nbar foo baz\nfoo bar baz blarp quux \n"; -&compare_output($answer, &get_logfile(1)); - +# echo '$(call my-foreach,a,x y z,$$(a)$$(a))'; \ +# echo '$(call my-if,,$$(info don't print this),$$(info do print this))' +# +# $answer = "xx yy zz\ndo print this\n"; # TEST eclipsing of arguments when invoking sub-calls -$makefile2 = &get_tmpfile; - -open(MAKEFILE,"> $makefile2"); - -print MAKEFILE <<'EOF'; - +run_make_test(q! all = $1 $2 $3 $4 $5 $6 $7 $8 $9 level1 = $(call all,$1,$2,$3,$4,$5) @@ -88,13 +71,8 @@ all: @echo $(call level1,1,2,3,4,5,6,7,8) @echo $(call level2,1,2,3,4,5,6,7,8) @echo $(call level3,1,2,3,4,5,6,7,8) -EOF - -close(MAKEFILE); - -&run_make_with_options($makefile2, "", &get_logfile); -$answer = "1 2 3 4 5 6 7 8 9\n1 2 3 4 5\n1 2 3\n1 2 3\n"; -&compare_output($answer,&get_logfile(1)); +!, + "", "1 2 3 4 5 6 7 8 9\n1 2 3 4 5\n1 2 3\n1 2 3\n"); # Ensure that variables are defined in global scope even in a $(call ...) @@ -108,3 +86,7 @@ all: ; @echo "$${X123-not set}" '', "\n"); 1; + +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/tests/scripts/functions/foreach b/tests/scripts/functions/foreach index 4d1a11d1..451839a2 100644 --- a/tests/scripts/functions/foreach +++ b/tests/scripts/functions/foreach @@ -53,8 +53,26 @@ $(foreach x,FOREACH,$(eval $(value mktarget)))', '', 'FOREACH'); +# Allow variable names with trailing space +run_make_test(q! +$(foreach \ + a \ +, b c d \ +, $(info $a)) +all:;@: +!, + "", "b\nc\nd\n"); -# TEST 2: Check some error conditions. +# Allow empty variable names. We still expand the body. + +run_make_test(' +x = $(foreach ,1 2 3,a) +y := $x + +all: ; @echo $y', + '', "a a a\n"); + +# Check some error conditions. run_make_test(' x = $(foreach ) @@ -66,12 +84,12 @@ all: ; @echo $y', 512); run_make_test(' -x = $(foreach ) +x = $(foreach x,y) y := $x all: ; @echo $y', '', - "#MAKEFILE#:2: *** insufficient number of arguments (1) to function 'foreach'. Stop.", + "#MAKEFILE#:2: *** insufficient number of arguments (2) to function 'foreach'. Stop.", 512); 1; diff --git a/tests/scripts/functions/sort b/tests/scripts/functions/sort index b5589103..e6e1343d 100644 --- a/tests/scripts/functions/sort +++ b/tests/scripts/functions/sort @@ -42,6 +42,10 @@ A boy captured_by days end, has jazz_and_a midnight moon_light rise run_make_test("FOO = a b\tc\rd\fe \f \f \f \f \ff all: ; \@echo \$(words \$(sort \$(FOO)))\n", - '', "5\n"); + '', "6\n"); 1; + +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/tests/scripts/misc/bs-nl b/tests/scripts/misc/bs-nl index 4fc3f639..fc323ce9 100644 --- a/tests/scripts/misc/bs-nl +++ b/tests/scripts/misc/bs-nl @@ -125,5 +125,103 @@ close(MAKEFILE); run_make_with_options($m2, '', get_logfile()); compare_output("foo bar\n", get_logfile(1)); +# Test different types of whitespace, and bsnl inside functions + +sub xlate +{ + $_ = $_[0]; + s/\\r/\r/g; + s/\\t/\t/g; + s/\\f/\f/g; + s/\\v/\v/g; + s/\\n/\n/g; + return $_; +} + +run_make_test(xlate(q! +$(foreach\r a \t , b\t c \r ,$(info $a \r ) ) +all:;@: +!), + '', "b \r \nc \r \n"); + +run_make_test(xlate(q! +all:;@:$(foreach\r a \t , b\t c \r ,$(info $a \r ) ) +!), + '', "b \r \nc \r \n"); + +run_make_test(xlate(q! +$(foreach \ +\r a \t\ + , b\t \ + c \r ,$(info \ + $a \r ) \ + ) +all:;@: +!), + '', "b \r \nc \r \n"); + +run_make_test(xlate(q! +all:;@:$(foreach \ +\r a \t\ + , b\t \ + c \r ,$(info \ + $a \r ) \ + ) +!), + '', "b \r \nc \r \n"); + +run_make_test(xlate(q! +define FOO +$(foreach +\r a \t + , b\t + c \r ,$(info + $a \r ) + ) +endef +$(FOO) +all:;@: +!), + '', "b \r \nc \r \n"); + +run_make_test(xlate(q! +define FOO +$(foreach +\r a \t + , b\t + c \r ,$(info + $a \r ) + ) +endef +all:;@:$(FOO) +!), + '', "b \r \nc \r \n"); + +# Test variables in recipes that expand to multiple lines + +run_make_test(q! +define var + +echo foo + + +echo bar +endef +all:;$(var) +!, + '', "echo foo\nfoo\necho bar\nbar\n"); + +run_make_test(q! +define var + +echo foo + +@ + +echo bar +endef +all:;$(var) +!, + '', "echo foo\nfoo\necho bar\nbar\n"); 1; diff --git a/variable.c b/variable.c index ca33a4c4..33b72951 100644 --- a/variable.c +++ b/variable.c @@ -1431,7 +1431,7 @@ parse_variable_definition (const char *p, struct variable *var) int wspace = 0; const char *e = NULL; - p = next_token (p); + NEXT_TOKEN (p); var->name = (char *)p; var->length = 0; @@ -1448,7 +1448,7 @@ parse_variable_definition (const char *p, struct variable *var) /* This begins a variable expansion reference. Make sure we don't treat chars inside the reference as assignment tokens. */ char closeparen; - int count; + c = *p++; if (c == '(') closeparen = ')'; @@ -1462,26 +1462,25 @@ parse_variable_definition (const char *p, struct variable *var) /* P now points past the opening paren or brace. Count parens or braces until it is matched. */ - count = 0; - for (; *p != '\0'; ++p) + for (unsigned int count = 1; *p != '\0'; ++p) { - if (*p == c) - ++count; - else if (*p == closeparen && --count < 0) + if (*p == closeparen && --count == 0) { ++p; break; } + if (*p == c) + ++count; } continue; } /* If we find whitespace skip it, and remember we found it. */ - if (isblank ((unsigned char)c)) + if (ISBLANK (c)) { wspace = 1; e = p - 1; - p = next_token (p); + NEXT_TOKEN (p); c = *p; if (c == '\0') return NULL; diff --git a/vpath.c b/vpath.c index 449779f9..2f1dafd5 100644 --- a/vpath.c +++ b/vpath.c @@ -208,7 +208,7 @@ construct_vpath_list (char *pattern, char *dirpath) #endif /* Skip over any initial separators and blanks. */ - while (*dirpath == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*dirpath)) + while (STOP_SET (*dirpath, MAP_BLANK|MAP_PATHSEP)) ++dirpath; /* Figure out the maximum number of VPATH entries and put it in @@ -218,7 +218,7 @@ construct_vpath_list (char *pattern, char *dirpath) maxelem = 2; p = dirpath; while (*p != '\0') - if (*p++ == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p)) + if (STOP_SET (*p++, MAP_BLANK|MAP_PATHSEP)) ++maxelem; vpath = xmalloc (maxelem * sizeof (const char *)); @@ -244,7 +244,7 @@ construct_vpath_list (char *pattern, char *dirpath) #else && *p != PATH_SEPARATOR_CHAR #endif - && !isblank ((unsigned char)*p)) + && !ISBLANK (*p)) ++p; len = p - v; @@ -266,7 +266,7 @@ construct_vpath_list (char *pattern, char *dirpath) } /* Skip over separators and blanks between entries. */ - while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p)) + while (STOP_SET (*p, MAP_BLANK|MAP_PATHSEP)) ++p; }