From 573ddaf6da9d06eecda354aa4b0e9d963d2c70d1 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 4 Feb 1993 00:58:10 +0000 Subject: Formerly job.c.~95~ --- job.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 2 deletions(-) (limited to 'job.c') 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. */ -- cgit v1.2.3