summaryrefslogtreecommitdiff
path: root/job.c
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2005-06-26 03:31:29 +0000
committerPaul Smith <psmith@gnu.org>2005-06-26 03:31:29 +0000
commitd6a7894d3a6bdb45def58b2fdfb0629233f4f38b (patch)
tree30cd386b442d5d2d6c6b2864be767a78630c767d /job.c
parentf388233b033ccae26e567fb573fd3d7a87c71744 (diff)
downloadgunmake-d6a7894d3a6bdb45def58b2fdfb0629233f4f38b.tar.gz
Fix Savannah bug # 1332: handle backslash-newline pairs in command scripts
according to POSIX rules.
Diffstat (limited to 'job.c')
-rw-r--r--job.c93
1 files changed, 39 insertions, 54 deletions
diff --git a/job.c b/job.c
index b805eda..1776aca 100644
--- a/job.c
+++ b/job.c
@@ -2363,12 +2363,10 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0;
for (p = line; *p != '\0'; ++p)
{
- if (ap > end)
- abort ();
+ assert (ap <= end);
if (instring)
{
- string_char:
/* Inside a string, just copy any char except a closing quote
or a backslash-newline combination. */
if (*p == instring)
@@ -2378,7 +2376,21 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
last_argument_was_empty = 1;
}
else if (*p == '\\' && p[1] == '\n')
- goto swallow_escaped_newline;
+ {
+ /* Backslash-newline is handled differently depending on what
+ kind of string we're in: inside single-quoted strings you
+ keep them; in double-quoted strings they disappear. */
+ if (instring == '"')
+ ++p;
+ else
+ {
+ *(ap++) = *(p++);
+ *(ap++) = *p;
+ }
+ /* If there's a TAB here, skip it. */
+ if (p[1] == '\t')
+ ++p;
+ }
else if (*p == '\n' && restp != NULL)
{
/* End of the command line. */
@@ -2418,37 +2430,21 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
break;
case '\\':
- /* Backslash-newline combinations are eaten. */
+ /* Backslash-newline has special case handling, ref POSIX.
+ We're in the fastpath, so emulate what the shell would do. */
if (p[1] == '\n')
{
- swallow_escaped_newline:
-
- /* Eat the backslash, the newline, and following whitespace,
- replacing it all with a single space. */
- p += 2;
-
- /* If there is a tab after a backslash-newline,
- remove it from the source line which will be echoed,
- since it was most likely used to line
- up the continued line with the previous one. */
- if (*p == '\t')
- /* Note these overlap and strcpy() is undefined for
- overlapping objects in ANSI C. The strlen() _IS_ right,
- since we need to copy the nul byte too. */
- bcopy (p + 1, p, strlen (p));
-
- if (instring)
- goto string_char;
- else
- {
- if (ap != new_argv[i])
- /* Treat this as a space, ending the arg.
- But if it's at the beginning of the arg, it should
- just get eaten, rather than becoming an empty arg. */
- goto end_of_arg;
- else
- p = next_token (p) - 1;
- }
+ /* Throw out the backslash and newline. */
+ ++p;
+
+ /* If there is a tab after a backslash-newline, remove it. */
+ if (p[1] == '\t')
+ ++p;
+
+ /* If there's nothing in this argument yet, skip any
+ whitespace before the start of the next word. */
+ if (ap == new_argv[i])
+ p = next_token (p + 1) - 1;
}
else if (p[1] != '\0')
{
@@ -2502,7 +2498,6 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
case ' ':
case '\t':
- end_of_arg:
/* We have the end of an argument.
Terminate the text of the argument. */
*ap++ = '\0';
@@ -2538,9 +2533,7 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
}
/* Ignore multiple whitespace chars. */
- p = next_token (p);
- /* Next iteration should examine the first nonwhite char. */
- --p;
+ p = next_token (p) - 1;
break;
default:
@@ -2672,23 +2665,15 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
}
else if (*p == '\\' && p[1] == '\n')
{
- /* Eat the backslash, the newline, and following whitespace,
- replacing it all with a single space (which is escaped
- from the shell). */
- p += 2;
-
- /* If there is a tab after a backslash-newline,
- remove it from the source line which will be echoed,
- since it was most likely used to line
- up the continued line with the previous one. */
- if (*p == '\t')
- bcopy (p + 1, p, strlen (p));
-
- p = next_token (p);
- --p;
- if (unixy_shell && !batch_mode_shell)
- *ap++ = '\\';
- *ap++ = ' ';
+ /* POSIX says we keep the backslash-newline, but throw out the
+ next char if it's a TAB. */
+ *(ap++) = '\\';
+ *(ap++) = *(p++);
+ *(ap++) = *p;
+
+ if (p[1] == '\t')
+ ++p;
+
continue;
}