summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>1993-02-04 00:58:10 +0000
committerRoland McGrath <roland@redhat.com>1993-02-04 00:58:10 +0000
commit573ddaf6da9d06eecda354aa4b0e9d963d2c70d1 (patch)
tree1a08a4364f47379ba7330180ceb861d4f6c4481d
parentdb545dffccd94782154d01a17430d08576198769 (diff)
downloadgunmake-573ddaf6da9d06eecda354aa4b0e9d963d2c70d1.tar.gz
Formerly job.c.~95~
-rw-r--r--job.c99
1 files changed, 97 insertions, 2 deletions
diff --git a/job.c b/job.c
index 01044c0..a8ffe4e 100644
--- a/job.c
+++ b/job.c
@@ -690,8 +690,103 @@ new_job (file)
/* Expand the command lines and store the results in LINES. */
lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
for (i = 0; i < cmds->ncommand_lines; ++i)
- lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
- file);
+ {
+ /* Collapse backslash-newline combinations that are inside variable
+ or function references. These are left alone by the parser so
+ that they will appear in the echoing of commands (where they look
+ nice); and collapsed by construct_command_argv when it tokenizes.
+ But letting them survive inside function invocations loses because
+ we don't want the functions to see them as part of the text. */
+
+ char *in, *out, *ref;
+
+ /* IN points to where in the line we are scanning.
+ OUT points to where in the line we are writing.
+ When we collapse a backslash-newline combination,
+ IN gets ahead out OUT. */
+
+ in = out = cmds->command_lines[i];
+ while ((ref = index (in, '$')) != 0)
+ {
+ ++ref; /* Move past the $. */
+
+ if (out != in)
+ /* Copy the text between the end of the last chunk
+ we processed (where IN points) and the new chunk
+ we are about to process (where REF points). */
+ bcopy (in, out, ref - in);
+
+ /* Move both pointers past the boring stuff. */
+ out += ref - in;
+ in = ref;
+
+ if (*ref == '(' || *ref == '{')
+ {
+ char openparen = *ref;
+ char closeparen = openparen == '(' ? ')' : '}';
+ int count;
+ char *p;
+
+ *out++ = *in++; /* Copy OPENPAREN. */
+ /* IN now points past the opening paren or brace.
+ Count parens or braces until it is matched. */
+ count = 0;
+ while (*in != '\0')
+ {
+ if (*in == closeparen && --count < 0)
+ break;
+ else if (*in == '\\' && in[1] == '\n')
+ {
+ /* We have found a backslash-newline inside a
+ variable or function reference. Eat it and
+ any following whitespace. */
+
+ int quoted = 0;
+ for (p = in - 1; p > ref && *p == '\\'; --p)
+ quoted = !quoted;
+
+ if (quoted)
+ /* There were two or more backslashes, so this is
+ not really a continuation line. We don't collapse
+ the quoting backslashes here as is done in
+ collapse_continuations, because the line will
+ be collapsed again after expansion. */
+ *out++ = *in++;
+ else
+ {
+ /* Skip the backslash, newline and
+ any following whitespace. */
+ in = next_token (in + 2);
+
+ /* Discard any preceding whitespace that has
+ already been written to the output. */
+ while (out > ref && isblank (out[-1]))
+ --out;
+
+ /* Replace it all with a single space. */
+ *out++ = ' ';
+ }
+ }
+ else
+ {
+ if (*in == openparen)
+ ++count;
+
+ *out++ = *in++;
+ }
+ }
+ }
+ }
+
+ /* There are no more references in this line to worry about.
+ Copy the remaining uninteresting text to the output. */
+ if (out != in)
+ strcpy (out, in);
+
+ /* Finally, expand the line. */
+ lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
+ file);
+ }
/* Start the command sequence, record it in a new
`struct child', and add that to the chain. */