mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-26 14:00:56 +00:00
[SV 46995] Strip leading/trailing space from variable names
* makeint.h: Change MAP_SPACE to MAP_NEWLINE, and add MAP_PATHSEP and MAP_SPACE which is now MAP_BLANK|MAP_NEWLINE. Create NEW_TOKEN(), END_OF_TOKEN(), ISBLANK(), ISSPACE() macros. * main.c (initialize_stopchar_map): Set MAP_NEWLINE only for newline characters. * Convert all uses of isblank() and isspace() to macros. * Examine all uses of isblank() (doesn't accept newlines) and change them wherever possible to ISSPACE() (does accept newlines). * function.c (func_foreach): Strip leading/trailing space. * variable.c (parse_variable_definition): Clean up. * tests/scripts/functions/foreach: Test settings and errors. * tests/scripts/functions/call: Rewrite to new-style. * tests/scripts/misc/bs-nl: Add many more tests for newlines.
This commit is contained in:
parent
2b9dd215d5
commit
e97159745d
15 changed files with 291 additions and 187 deletions
|
@ -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')
|
||||
{
|
||||
|
|
2
expand.c
2
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:
|
||||
|
|
47
function.c
47
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')
|
||||
|
|
|
@ -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++);
|
||||
|
|
71
job.c
71
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;
|
||||
|
|
29
main.c
29
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++;
|
||||
}
|
||||
|
|
58
makeint.h
58
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 <direct.h>
|
||||
|
@ -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
|
||||
|
|
15
misc.c
15
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;
|
||||
}
|
||||
|
||||
|
|
42
read.c
42
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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
17
variable.c
17
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;
|
||||
|
|
8
vpath.c
8
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue