Formerly job.c.~95~
authorRoland McGrath <roland@redhat.com>
Thu, 4 Feb 1993 00:58:10 +0000 (00:58 +0000)
committerRoland McGrath <roland@redhat.com>
Thu, 4 Feb 1993 00:58:10 +0000 (00:58 +0000)
job.c

diff --git a/job.c b/job.c
index 01044c0..a8ffe4e 100644 (file)
--- 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.  */