home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / BASH_112.ZIP / BASH-112.TAR / bash-1.12 / subst.c < prev    next >
C/C++ Source or Header  |  1993-07-20  |  90KB  |  3,494 lines

  1. /* substitutions.c -- The part of the shell that does parameter,
  2.    command, and globbing substitutions. */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <pwd.h>
  25. #include <signal.h>
  26. #include <string.h>
  27. #include "shell.h"
  28. #include "flags.h"
  29. #include "alias.h"
  30. #include "jobs.h"
  31. #include "filecntl.h"
  32. #include <readline/history.h>
  33. #include <glob/fnmatch.h>
  34. #include <errno.h>                        /* 3/93 ROB */
  35.  
  36. /* The size that strings change by. */
  37. #define DEFAULT_ARRAY_SIZE 512
  38.  
  39. /* How to quote and dequote the character C. */
  40. #define QUOTE_CHAR(c)   ((unsigned char)(c) | 0x80)
  41. #define DEQUOTE_CHAR(c) ((unsigned char)(c) & 0x7f)
  42. #define QUOTED_CHAR(c)  ((unsigned char)(c) > 0x7f)
  43.  
  44. /* Process ID of the last command executed within command substitution. */
  45. pid_t last_command_subst_pid = NO_PID;
  46.  
  47. /* Some forward declarations. */
  48.  
  49. extern WORD_LIST *expand_string (), *expand_word (), *list_string ();
  50. extern char *string_list ();
  51. extern WORD_DESC *make_word ();
  52. extern WORD_DESC *copy_word ();
  53. extern WORD_LIST *copy_word_list();
  54.  
  55. #if defined(__EMX__)
  56. #define INCL_DOSPROCESS
  57. #include <os2.h>
  58. extern HFILE        pipeReadHandle,
  59.                     pipeWriteHandle;
  60. extern VOID APIENTRY    childExitListProc(void);
  61. #endif
  62.  
  63. #if defined(__DEBUG__)
  64. extern FILE        *debugFile;
  65. #define DEBUG_OUT writeDebugInfo
  66. #endif
  67.  
  68. static WORD_LIST *expand_string_internal (), *expand_words_internal ();
  69. static char *quote_string (), *dequote_string ();
  70. static int unquoted_substring ();
  71. static void quote_list ();
  72.  
  73. /* **************************************************************** */
  74. /*                                    */
  75. /*            Utility Functions                */
  76. /*                                    */
  77. /* **************************************************************** */
  78.  
  79. /* Cons a new string from STRING starting at START and ending at END,
  80.    not including END. */
  81. char *
  82. substring (string, start, end)
  83.      char *string;
  84.      int start, end;
  85. {
  86.   register int len = end - start;
  87.   register char *result = (char *)xmalloc (len + 1);
  88.  
  89.   strncpy (result, string + start, len);
  90.   result[len] = '\0';
  91.   return (result);
  92. }
  93.  
  94. /* Just like string_extract, but doesn't hack backslashes or any of
  95.    that other stuff. */
  96. char *
  97. string_extract_verbatim (string, sindex, charlist)
  98.      char *string, *charlist;
  99.      int *sindex;
  100. {
  101.   register int i = *sindex;
  102.   int c;
  103.   char *temp;
  104.  
  105.   while ((c = string[i]) && (!member (c, charlist))) i++;
  106.   temp = (char *)xmalloc (1 + (i - *sindex));
  107.   strncpy (temp, string + (*sindex), i - (*sindex));
  108.   temp[i - (*sindex)] = '\0';
  109.   *sindex = i;
  110.   return (temp);
  111. }
  112.  
  113. /* Extract a substring from STRING, starting at SINDEX and ending with
  114.    one of the characters in CHARLIST.  Don't make the ending character
  115.    part of the string.  Leave SINDEX pointing at the ending character.
  116.    Understand about backslashes in the string. */
  117. char *
  118. string_extract (string, sindex, charlist)
  119.      char *string, *charlist;
  120.      int *sindex;
  121. {
  122.   register int c, i = *sindex;
  123.   char *temp;
  124.  
  125.   while (c = string[i]) {
  126.     if (c == '\\')
  127.       if (string[i + 1])
  128.     i++;
  129.       else
  130.     break;
  131.     else
  132.       if (member (c, charlist))
  133.     break;
  134.     i++;
  135.   }
  136.   temp = (char *)xmalloc (1 + (i - *sindex));
  137.   strncpy (temp, string + (*sindex), i - (*sindex));
  138.   temp[i - (*sindex)] = '\0';
  139.   *sindex = i;
  140.   return (temp);
  141. }
  142.  
  143. /* Remove backslashes which are quoting backquotes from STRING.  Modifies
  144.    STRING, and returns a pointer to it. */
  145. char *
  146. de_backslash (string)
  147.      char *string;
  148. {
  149.   register int i, l = strlen (string);
  150.  
  151.   for (i = 0; i < l; i++)
  152.     if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
  153.                   string[i + 1] == '$'))
  154.       strcpy (&string[i], &string[i + 1]);
  155.   return (string);
  156. }
  157.  
  158. /* Replace instances of \! in a string with !. */
  159. void
  160. unquote_bang (string)
  161.      char *string;
  162. {
  163.   register int i, j;
  164.   register char *temp;
  165.  
  166.   temp = (char *)alloca (1 + strlen (string));
  167.  
  168.   for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
  169.     {
  170.       if (string[i] == '\\' && string[i + 1] == '!')
  171.     {
  172.       temp[j] = '!';
  173.       i++;
  174.     }
  175.     }
  176.   strcpy (string, temp);
  177. }
  178.  
  179. /* Extract the $( construct in STRING, and return a new string.
  180.    Start extracting at (SINDEX) as if we had just seen "$(".
  181.    Make (SINDEX) get the position just after the matching ")". */
  182. char *
  183. extract_command_subst (string, sindex)
  184.      char *string;
  185.      int *sindex;
  186. {
  187.   char *extract_delimited_string ();
  188.  
  189.   return (extract_delimited_string (string, sindex, "$(", "(", ")"));
  190. }
  191.  
  192. /* Extract the $[ construct in STRING, and return a new string.
  193.    Start extracting at (SINDEX) as if we had just seen "$[".
  194.    Make (SINDEX) get the position just after the matching "]".
  195.  
  196.    Strictly speaking, according to the letter of POSIX.2, arithmetic
  197.    substitutions cannot be nested.  This code allows nesting, however,
  198.    and it is fully implemented. */
  199. char *
  200. extract_arithmetic_subst (string, sindex)
  201.      char *string;
  202.      int *sindex;
  203. {
  204.   char *extract_delimited_string ();
  205.  
  206.   return (extract_delimited_string (string, sindex, "$[", "[", "]"));
  207. }
  208.  
  209. /* Extract and create a new string from the contents of STRING, a
  210.    character string delimited with OPENER and CLOSER.  SINDEX is
  211.    the address of an int describing the current offset in STRING;
  212.    it should point to just after the first OPENER found.  On exit,
  213.    SINDEX gets the position just after the matching CLOSER.  If
  214.    OPENER is more than a single character, ALT_OPENER, if non-null,
  215.    contains a character string that can also match CLOSER and thus
  216.    needs to be skipped. */
  217. char *
  218. extract_delimited_string (string, sindex, opener, alt_opener, closer)
  219.      char *string;
  220.      int *sindex;
  221.      char *opener, *alt_opener, *closer;
  222. {
  223.   register int i, c, l;
  224.   int pass_character, nesting_level;
  225.   int delimiter, delimited_nesting_level;
  226.   int len_closer, len_opener, len_alt_opener;
  227.   char *result;
  228.  
  229.   len_opener = strlen (opener);
  230.   len_alt_opener = alt_opener ? strlen (alt_opener) : 0;
  231.   len_closer = strlen (closer);
  232.  
  233.   pass_character = delimiter = delimited_nesting_level = 0;
  234.  
  235.   nesting_level = 1;
  236.  
  237.   for (i = *sindex; c = string[i]; i++)
  238.     {
  239.       if (pass_character)
  240.     {
  241.       pass_character = 0;
  242.       continue;
  243.     }
  244.  
  245.       if (c == '\\')
  246.     {
  247.       if ((delimiter == '"') &&
  248.           (member (string[i + 1], slashify_in_quotes)))
  249.         {
  250.           pass_character++;
  251.           continue;
  252.         }
  253.     }
  254.  
  255.       if (!delimiter || delimiter == '"')
  256.     {
  257.       if (strncmp (string + i, opener, len_opener) == 0)
  258.         {
  259.           if (!delimiter)
  260.         nesting_level++;
  261.           else
  262.         delimited_nesting_level++;
  263.  
  264.           i += len_opener - 1;
  265.           continue;
  266.         }
  267.  
  268.       if (len_alt_opener &&
  269.           strncmp (string + i, alt_opener, len_alt_opener) == 0)
  270.         {
  271.           if (!delimiter)
  272.         nesting_level++;
  273.           else
  274.         delimited_nesting_level++;
  275.  
  276.           i += len_alt_opener - 1;
  277.           continue;
  278.         }
  279.  
  280.       if (strncmp (string + i, closer, len_closer) == 0)
  281.         {
  282.           i += len_closer - 1;
  283.  
  284.           if (delimiter && delimited_nesting_level)
  285.         delimited_nesting_level--;
  286.  
  287.           if (!delimiter)
  288.         {
  289.           nesting_level--;
  290.           if (nesting_level == 0)
  291.             break;
  292.         }
  293.         }
  294.     }
  295.  
  296.       if (delimiter)
  297.     {
  298.       if (c == delimiter || delimiter == '\\')
  299.         delimiter = 0;
  300.       continue;
  301.     }
  302.       else
  303.     {
  304.       if (c == '"' || c == '\'' || c == '\\')
  305.         delimiter = c;
  306.     }
  307.     }
  308.  
  309.   l = i - *sindex;
  310.   result = (char *)xmalloc (1 + l);
  311.   strncpy (result, &string[*sindex], l);
  312.   result[l] = '\0';
  313.   *sindex = i;
  314.  
  315.   if (!c && (delimiter || nesting_level))
  316.     {
  317.       report_error ("bad substitution: %s%s", opener, result);
  318.       free (result);
  319.       longjmp (top_level, DISCARD);
  320.     }
  321.   return (result);
  322. }
  323.  
  324. /* An artifact for extracting the contents of a quoted string.  Since the
  325.    string is about to be evaluated, we pass everything through, and only
  326.    strip backslash before backslash or quote. */
  327. /* This is a mini state machine. */
  328. char *
  329. string_extract_double_quoted (string, sindex)
  330.      char *string;
  331.      int *sindex;
  332. {
  333.   register int c, j, i;
  334.   char *temp;            /* The new string we return. */
  335.   int pass_next, backquote;    /* State variables for the machine. */
  336.  
  337.   pass_next = backquote = 0;
  338.   temp = (char *)xmalloc (1 + (strlen (string) - *sindex));
  339.  
  340.   for (j = 0, i = *sindex; c = string[i]; i++)
  341.     {
  342.       /* Process a character that was quoted by a backslash. */
  343.       if (pass_next)
  344.     {
  345.       /* Posix.2 sez:
  346.  
  347.          ``The backslash shall retain its special meaning as an escape
  348.          character only when followed by one of the characters:
  349.              $    `    "    \    <newline>''.
  350.  
  351.          We handle the double quotes here.  expand_word_internal handles
  352.          the rest. */
  353.       if (c != '"')
  354.         temp[j++] = '\\';
  355.           temp[j++] = c;
  356.           pass_next = 0;
  357.           continue;
  358.     }
  359.  
  360.       /* A backslash protects the next character.  The code just above
  361.          handles preserving the backslash in front of any character but
  362.          a double quote. */
  363.       if (c == '\\')
  364.     {
  365.       pass_next++;
  366.       continue;
  367.     }
  368.  
  369.       /* Inside backquotes, ``the portion of the quoted string from the
  370.      initial backquote and the characters up to the next backquote
  371.      that is not preceded by a backslash, having escape characters
  372.      removed, defines that command''. */
  373.       if (backquote)
  374.         {
  375.           if (c == '`')
  376.             backquote = 0;
  377.       temp[j++] = c;
  378.       continue;
  379.         }
  380.  
  381.       if (c == '`')
  382.         {
  383.           temp[j++] = c;
  384.           backquote++;
  385.           continue;
  386.         }
  387.  
  388.       /* Pass everything between `$(' and the matching `)' through verbatim. */
  389.       if (c == '$' && string[i + 1] == '(')
  390.     {
  391.       register int t;
  392.       int si;
  393.       char *ret;
  394.  
  395.       si = i + 2;
  396.       ret = extract_delimited_string (string, &si, "$(", "(", ")");
  397.  
  398.       temp[j++] = '$';
  399.       temp[j++] = '(';
  400.  
  401.       for (t = 0; ret[t]; t++)
  402.         temp[j++] = ret[t];
  403.  
  404.       i = si;
  405.       temp[j++] = string[i];
  406.       free (ret);
  407.       continue;
  408.     }
  409.  
  410.       /* An unescaped double quote serves to terminate the string. */
  411.       if (c == '"')
  412.         break;
  413.  
  414.       /* Add the character to the quoted string we're accumulating. */
  415.       temp[j++] = c;
  416.     }
  417.   temp[j] = '\0';
  418.   *sindex = i;
  419.   return (temp);
  420. }
  421.  
  422. /* Extract the name of the variable to bind to from the assignment string. */
  423. char *
  424. assignment_name (string)
  425.      char *string;
  426. {
  427.   int offset = assignment (string);
  428.   char *temp;
  429.   if (!offset) return (char *)NULL;
  430.   temp = (char *)xmalloc (offset + 1);
  431.   strncpy (temp, string, offset);
  432.   temp[offset] = '\0';
  433.   return (temp);
  434. }
  435.  
  436. /* Return a single string of all the words in LIST.  SEP is the separator
  437.    to put between individual elements of LIST in the output string. */
  438.  
  439. static char *
  440. string_list_internal (list, sep)
  441.      WORD_LIST *list;
  442.      char *sep;
  443. {
  444.   char *result = (char *)NULL;
  445.   int sep_len;
  446.  
  447.   sep_len = strlen (sep);
  448.  
  449.   while (list)
  450.     {
  451.       /* Can't simply let xrealloc malloc the bytes for us the first time
  452.          because of the strcat (result, ...) -- we need to make sure result
  453.          is initialized to null after being allocated initially. */
  454.       if (!result)
  455.     result = savestring ("");
  456.  
  457.       result = (char *)xrealloc
  458.     (result, 2 + sep_len + strlen (result) + strlen (list->word->word));
  459.       strcat (result, list->word->word);
  460.       if (list->next)
  461.     strcat (result, sep);
  462.       list = list->next;
  463.     }
  464.   return (result);
  465. }
  466.  
  467. /* Return a single string of all the words present in LIST, separating
  468.    each word with a space. */
  469. char *
  470. string_list (list)
  471.      WORD_LIST *list;
  472. {
  473.   return (string_list_internal (list, " "));
  474. }
  475.  
  476. /* Return a single string of all the words present in LIST, obeying the
  477.    quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2, "If the
  478.    expansion [of $*] appears within a double quoted string, it expands
  479.    to a single field with the value of each parameter separated by the
  480.    first character of the IFS variable, or by a <space> if IFS is unset
  481.    [or null]." */
  482.  
  483. char *
  484. string_list_dollar_star (list)
  485.      WORD_LIST *list;
  486. {
  487.   char *ifs = get_string_value ("IFS");
  488.   char sep[2];
  489.  
  490.   if (!ifs)
  491.     sep[0] = ' ';
  492.   else if (!*ifs)
  493.     sep[0] = '\0';
  494.   else
  495.     sep[0] = *ifs;
  496.  
  497.   sep[1] = '\0';
  498.  
  499.   return (string_list_internal (list, sep));
  500. }
  501.  
  502. /* Return the list of words present in STRING.  Separate the string into
  503.    words at any of the characters found in SEPARATORS.  If QUOTED is
  504.    non-zero then word in the list will have its quoted flag set, otherwise
  505.    the quoted flag is left as make_word () deemed fit.
  506.  
  507.    This obeys the P1003.2 draft 11 word splitting semantics.  If `separators'
  508.    is exactly <space><tab><newline>, then the splitting algorithm is that of
  509.    the Bourne shell, which treats any sequence of characters from `separators'
  510.    as a delimiter.  If IFS is unset, which results in `separators' being set
  511.    to "", no splitting occurs.  If separators has some other value, the
  512.    following rules are applied (`IFS white space' means zero or more
  513.    occurrences of <space>, <tab>, or <newline>, as long as those characters
  514.    are in `separators'):
  515.  
  516.     1) IFS white space is ignored at the start and the end of the
  517.        string.
  518.     2) Each occurrence of a character in `separators' that is not
  519.        IFS white space, along with any adjacent occurrences of
  520.        IFS white space delimits a field.
  521.     3) Any nonzero-length sequence of IFS white space delimits a field.
  522.    */
  523.  
  524. /* BEWARE!  list_string strips null arguments.  Don't call it twice and
  525.    expect to have "" preserved! */
  526.  
  527. /* Is C a quoted NULL character? */
  528. #define QUOTED_NULL(c) ((unsigned char)(c) == (unsigned char)0x80)
  529.  
  530. /* Perform quoted null character removal on STRING. */
  531. void
  532. remove_quoted_nulls (string)
  533.      char *string;
  534. {
  535.   register char *s;
  536.  
  537.   for (s = string; s && *s; s++)
  538.     {
  539.       if (QUOTED_NULL (*s))
  540.     {
  541.       strcpy (s, s + 1);
  542.       s--;
  543.     }
  544.     }
  545. }
  546.  
  547. /* Perform quoted null character removal on each element of LIST.
  548.    This modifies LIST. */
  549. word_list_remove_quoted_nulls (list)
  550.      WORD_LIST *list;
  551. {
  552.   register WORD_LIST *t;
  553.  
  554.   t = list;
  555.  
  556.   while (t)
  557.     {
  558.       remove_quoted_nulls (t->word->word);
  559.       t = t->next;
  560.     }
  561. }
  562.  
  563. /* This performs word splitting and quoted null character removal on
  564.    STRING. */
  565.  
  566. #define issep(c)    (member ((c), separators))
  567. #define spctabnl(c)    ((c) == ' '|| (c) == '\t' || (c) == '\n')
  568.  
  569. WORD_LIST *
  570. list_string (string, separators, quoted)
  571.      register char *string, *separators;
  572.      int quoted;
  573. {
  574.   WORD_LIST *result = (WORD_LIST *)NULL;
  575.   char *current_word = (char *)NULL, *s;
  576.   int sindex = 0;
  577.   int sh_style_split;
  578.  
  579.   if (!string || !*string)
  580.     return ((WORD_LIST *)NULL);
  581.  
  582.   sh_style_split = separators && *separators && (!strcmp (separators, " \t\n"));
  583.  
  584.   /* Remove sequences of whitespace at the beginning and end of STRING, as
  585.      long as those characters appear in IFS. */
  586.   for (s = string; *s && spctabnl (*s) && issep (*s); s++);
  587.   if (!*s)
  588.     return ((WORD_LIST *)NULL);
  589.   string = s;
  590.   s += strlen (s) - 1;
  591.   for ( ; s > string && *s && spctabnl (*s) & issep (*s); s--);
  592.   if (!*s)
  593.     return ((WORD_LIST *)NULL);
  594.   *++s = '\0';
  595.  
  596.   /* OK, now STRING points to a word that does not begin with white space.
  597.      The splitting algorithm is:
  598.          extract a word, stopping at a separator
  599.          skip sequences of spc, tab, or nl as long as they are separators
  600.      This obeys the field splitting rules in Posix.2 draft 11.x. */
  601.  
  602.   while (string[sindex])
  603.     {
  604.       current_word = string_extract_verbatim (string, &sindex, separators);
  605.       if (!current_word)
  606.         break;
  607.  
  608.       /* If we have a quoted empty string, add a quoted null argument.  We
  609.      want to preserve the quoted null character iff this is a quoted
  610.      empty string; otherwise the quoted null characters are removed
  611.      below. */
  612.       if (QUOTED_NULL (current_word[0]) && current_word[1] == '\0')
  613.     {
  614.       WORD_DESC *t = make_word (" ");
  615.       t->quoted++;
  616.       t->word[0] = (unsigned char)QUOTE_CHAR ('\0');
  617.       result = make_word_list (t, result);
  618.     }
  619.  
  620.       /* If we have something, then add it regardless. */
  621.       else if (strlen (current_word))
  622.     {
  623.       register char *temp_string;
  624.  
  625.       /* Perform quoted null character removal on the current word. */
  626.        for (temp_string = current_word; *temp_string; temp_string++)
  627.         if (QUOTED_NULL (*temp_string))
  628.           {
  629.         strcpy (temp_string, temp_string + 1);
  630.         temp_string--;
  631.           }
  632.  
  633.       result = make_word_list (make_word (current_word), result);
  634.       if (quoted)
  635.         result->word->quoted++;
  636.     }
  637.  
  638.       /* If we're not doing sequences of separators in the traditional
  639.      Bourne shell style, then add a quoted null argument. */
  640.  
  641.       else if (!sh_style_split && !spctabnl (string[sindex]))
  642.     {
  643.       result = make_word_list (make_word (""), result);
  644.       result->word->quoted++;
  645.     }
  646.  
  647.       free (current_word);
  648.  
  649.       /* Move past the current separator character. */
  650.       if (string[sindex])
  651.         sindex++;
  652.  
  653.       /* Now skip sequences of space, tab, or newline characters if they are
  654.          in the list of separators. */
  655.       while (string[sindex] &&
  656.          spctabnl (string[sindex]) &&
  657.          issep (string[sindex]))
  658.     sindex++;
  659.  
  660.     }
  661.   return (WORD_LIST *)reverse_list (result);
  662. }
  663.  
  664. /* Given STRING, an assignment string, get the value of the right side
  665.    of the `=', and bind it to the left side.  If EXPAND is true, then
  666.    perform parameter expansion, command substitution, and arithmetic
  667.    expansion on the right-hand side.  Perform tilde expansion in any
  668.    case.  Do not perform word splitting on the result of expansion. */
  669. do_assignment_internal (string, expand)
  670.      char *string;
  671.      int expand;
  672. {
  673.   int offset = assignment (string);
  674.   char *name = savestring (string);
  675.   char *value = (char *)NULL;
  676.   SHELL_VAR *entry = (SHELL_VAR *)NULL;
  677.  
  678.   if (name[offset] == '=')
  679.     {
  680.       char *tilde_expand (), *string_list ();
  681.       WORD_LIST *list, *expand_string_unsplit ();
  682.       char *temp;
  683.  
  684.       name[offset] = 0;
  685.       temp = name + offset + 1;
  686.  
  687.       if (expand)
  688.     {
  689.       if (index (temp, '~'))
  690.         temp = tilde_expand (temp);
  691.       else
  692.         temp = savestring (temp);
  693.  
  694.       list = expand_string_unsplit (temp, 0);
  695.  
  696.       if (list)
  697.         {
  698.           value = string_list (list);
  699.           dispose_words (list);
  700.         }
  701.       free (temp);
  702.     }
  703.       else
  704.     value = savestring (temp);
  705.     }
  706.  
  707.   if (!value)
  708.     value = savestring ("");
  709.  
  710.   entry = bind_variable (name, value);
  711.  
  712.   if (echo_command_at_execute)
  713.     {
  714.       extern char *indirection_level_string ();
  715.       fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
  716.     }
  717.  
  718.   /* Yes, here is where the special shell variables get tested for.
  719.      Don't ask me, I just work here.  This is really stupid.  I would
  720.      swear, but I've decided that that is an impolite thing to do in
  721.      source that is to be distributed around the net, even if this code
  722.      is totally brain-damaged. */
  723.  
  724.   /* if (strcmp (name, "PATH") == 0) Yeeecchhh!!!*/
  725.   stupidly_hack_special_variables (name);
  726.  
  727.   if (entry)
  728.     entry->attributes &= ~att_invisible;
  729.   if (value)
  730.     free (value);
  731.   free (name);
  732. }
  733.  
  734. /* Perform the assignment statement in STRING, and expand the
  735.    right side by doing command and parameter expansion. */
  736. do_assignment (string)
  737.      char *string;
  738. {
  739.   do_assignment_internal (string, 1);
  740. }
  741.  
  742. /* Given STRING, an assignment string, get the value of the right side
  743.    of the `=', and bind it to the left side.  Do not do command and
  744.    parameter substitution on the right hand side. */
  745. do_assignment_no_expand (string)
  746.      char *string;
  747. {
  748.   do_assignment_internal (string, 0);
  749. }
  750.  
  751. /* Most of the substitutions must be done in parallel.  In order
  752.    to avoid using tons of unclear goto's, I have some functions
  753.    for manipulating malloc'ed strings.  They all take INDEX, a
  754.    pointer to an integer which is the offset into the string
  755.    where manipulation is taking place.  They also take SIZE, a
  756.    pointer to an integer which is the current length of the
  757.    character array for this string. */
  758.  
  759. /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
  760.    of space allocated to TARGET.  SOURCE can be NULL, in which
  761.    case nothing happens.  Gets rid of SOURCE by free ()ing it.
  762.    Returns TARGET in case the location has changed. */
  763. char *
  764. sub_append_string (source, target, index, size)
  765.      char *source, *target;
  766.      int *index, *size;
  767. {
  768.   if (source)
  769.     {
  770.       while ((int)strlen (source) >= (int)(*size - *index))
  771.     target = (char *)xrealloc (target, *size += DEFAULT_ARRAY_SIZE);
  772.  
  773.       strcat (target, source);
  774.       *index += strlen (source);
  775.  
  776.       free (source);
  777.     }
  778.   return (target);
  779. }
  780.  
  781. /* Append the textual representation of NUMBER to TARGET.
  782.    INDEX and SIZE are as in SUB_APPEND_STRING. */
  783. char *
  784. sub_append_number (number, target, index, size)
  785.      int number, *index, *size;
  786.      char *target;
  787. {
  788.   char *temp = (char *)xmalloc (10);
  789.   sprintf (temp, "%d", number);
  790.   return (sub_append_string (temp, target, index, size));
  791. }
  792.  
  793. /* Return the word list that corresponds to `$*'. */
  794. WORD_LIST *
  795. list_rest_of_args ()
  796. {
  797.   register WORD_LIST *list = (WORD_LIST *)NULL;
  798.   register WORD_LIST *args = rest_of_args;
  799.   int i;
  800.  
  801.   for (i = 1; i < 10; i++)
  802.     if (dollar_vars[i])
  803.       list = make_word_list (make_word (dollar_vars[i]), list);
  804.   while (args)
  805.     {
  806.       list = make_word_list (make_word (args->word->word), list);
  807.       args = args->next;
  808.     }
  809.   return ((WORD_LIST *)reverse_list (list));
  810. }
  811.  
  812. /* Make a single large string out of the dollar digit variables,
  813.    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
  814.    case of "$*" with respect to IFS. */
  815. char *
  816. string_rest_of_args (dollar_star)
  817.      int dollar_star;
  818. {
  819.   register WORD_LIST *list = list_rest_of_args ();
  820.   char *string;
  821.  
  822.   if (!dollar_star)
  823.     string = string_list (list);
  824.   else
  825.     string = string_list_dollar_star (list);
  826.  
  827.   dispose_words (list);
  828.   return (string);
  829. }
  830.  
  831. /***************************************************
  832.  *                           *
  833.  *       Functions to Expand a String           *
  834.  *                           *
  835.  ***************************************************/
  836.  
  837. /* Perform parameter expansion, command substitution, and arithmetic
  838.    expansion on STRING, as if it were a word.  Leave the result quoted. */
  839. static WORD_LIST *
  840. expand_string_internal (string, quoted)
  841.      char *string;
  842.      int quoted;
  843. {
  844.   WORD_DESC *make_word (), *temp = make_word (string);
  845.   WORD_LIST *tresult, *expand_word_internal ();
  846.  
  847.   tresult  = expand_word_internal (temp, quoted, (int *)NULL, (int *)NULL);
  848.   dispose_word (temp);
  849.   return (tresult);
  850. }
  851.  
  852. /* Expand STRING by performing parameter expansion, command substitution,
  853.    and arithmetic expansion.  Dequote the resulting WORD_LIST before
  854.    returning it, but do not perform word splitting.  The call to
  855.    remove_quoted_nulls () is in here because word splitting normally
  856.    takes care of quote removal. */
  857. WORD_LIST *
  858. expand_string_unsplit (string, quoted)
  859.      char *string;
  860.      int quoted;
  861. {
  862.   WORD_LIST *value = expand_string_internal (string, quoted);
  863.  
  864.   if (value && value->word)
  865.     remove_quoted_nulls (value->word->word);
  866.  
  867.   if (value)
  868.     dequote_list (value);
  869.   return (value);
  870. }
  871.  
  872. /* Expand STRING just as if you were expanding a word.  This also returns
  873.    a list of words.  Note that filename globbing is *NOT* done for word
  874.    or string expansion, just when the shell is expanding a command.  This
  875.    does parameter expansion, command substitution, arithmetic expansion,
  876.    and word splitting.  Dequote the resultant WORD_LIST before returning. */
  877. WORD_LIST *
  878. expand_string (string, quoted)
  879.      char *string;
  880.      int quoted;
  881. {
  882.   WORD_LIST *value = expand_string_internal (string, quoted);
  883.   WORD_LIST *result, *word_list_split ();
  884.  
  885.   result = word_list_split (value);
  886.   dispose_words (value);
  887.   if (result)
  888.     dequote_list (result);
  889.   return (result);
  890. }
  891.  
  892. /* Expand STRING just as if you were expanding a word, but do not dequote
  893.    the resultant WORD_LIST.  This is called only from within this file,
  894.    and is used to correctly preserve quoted characters when expanding
  895.    things like ${1+"$@"}.  This does parameter expansion, command
  896.    subsitution, arithmetic expansion, and word splitting. */
  897. static WORD_LIST *
  898. expand_string_leave_quoted (string, quoted)
  899.      char *string;
  900.      int quoted;
  901. {
  902.   WORD_LIST *tlist  = expand_string_internal (string, quoted);
  903.   WORD_LIST *tresult, *word_list_split ();
  904.  
  905.   tresult = word_list_split (tlist);
  906.   dispose_words (tlist);
  907.   return (tresult);
  908. }
  909.  
  910. /***************************************************
  911.  *                           *
  912.  *    Functions to handle quoting chars       *
  913.  *                           *
  914.  ***************************************************/
  915.  
  916. /* I'm going to have to rewrite expansion because filename globbing is
  917.    beginning to make the entire arrangement ugly.  I'll do this soon. */
  918. dequote_list (list)
  919.      register WORD_LIST *list;
  920. {
  921.   register char *s;
  922.  
  923.   while (list)
  924.     {
  925.       s = dequote_string (list->word->word);
  926.       free (list->word->word);
  927.       list->word->word = s;
  928.       list = list->next;
  929.     }
  930. }
  931.  
  932. /* Quote the string S.  Return a new string. */
  933. static char *
  934. quote_string (s)
  935.      char *s;
  936. {
  937.   unsigned char *result;
  938.  
  939.   /* If S is an empty string then simply create a string consisting of a
  940.      quoted null. */
  941.   if (s[0] == '\0')
  942.     {
  943.       result = (unsigned char *)xmalloc (2);
  944.       result[0] = (unsigned char)QUOTE_CHAR ('\0');
  945.       result[1] = '\0';
  946.     }
  947.   else
  948.     {
  949.       register unsigned char *t;
  950.       result = (unsigned char *)savestring (s);
  951.       for (t = result; t && *t ; t++)
  952.     *t |= 0x80;
  953.     }
  954.   return ((char *)result);
  955. }
  956.  
  957. /* De-quoted quoted characters in string s. */
  958. static char *
  959. dequote_string (s)
  960.      char *s;
  961. {
  962.   register unsigned char *t;
  963.   unsigned char *result;
  964.  
  965.   result = (unsigned char *)savestring (s);
  966.   for (t = result; t && *t ; t++)
  967.     *t = DEQUOTE_CHAR (*t);
  968.  
  969.   return ((char *)result);
  970. }
  971.  
  972. /* Quote the entire WORD_LIST list. */
  973. static void
  974. quote_list (list)
  975.      WORD_LIST *list;
  976. {
  977.   register WORD_LIST *w;
  978.  
  979.   for (w = list; w; w = w->next)
  980.     {
  981.       char *t = w->word->word;
  982.       w->word->word = quote_string (t);
  983.       free (t);
  984.       w->word->quoted = 1;
  985.     }
  986. }
  987.  
  988. /* **************************************************************** */
  989. /*                                    */
  990. /*            Functions for Removing Patterns            */
  991. /*                                    */
  992. /* **************************************************************** */
  993.  
  994. /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
  995.    can have one of 4 values:
  996.     RP_LONG_LEFT    remove longest matching portion at start of PARAM
  997.     RP_SHORT_LEFT    remove shortest matching portion at start of PARAM
  998.     RP_LONG_RIGHT    remove longest matching portion at end of PARAM
  999.     RP_SHORT_RIGHT    remove shortest matching portion at end of PARAM
  1000. */
  1001.  
  1002. #define RP_LONG_LEFT    1
  1003. #define RP_SHORT_LEFT    2
  1004. #define RP_LONG_RIGHT    3
  1005. #define RP_SHORT_RIGHT    4
  1006.  
  1007. static char *
  1008. remove_pattern (param, pattern, op)
  1009.      char *param, *pattern;
  1010.      int op;
  1011. {
  1012.   register int len = param ? strlen (param) : 0;
  1013.   register char *end = param + len;
  1014.   register char *p, *ret, c;
  1015.  
  1016.   if (pattern == NULL || *pattern == '\0')    /* minor optimization */
  1017.     return (savestring (param));
  1018.  
  1019.   if (param == NULL || *param == '\0')
  1020.     return (param);
  1021.  
  1022.   switch (op)
  1023.     {
  1024.       case RP_LONG_LEFT:    /* remove longest match at start */
  1025.     for (p = end; p >= param; p--)
  1026.       {
  1027.         c = *p; *p = '\0';
  1028.         if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
  1029.           {
  1030.         *p = c;
  1031.         return (savestring (p));
  1032.           }
  1033.         *p = c;
  1034.       }
  1035.     break;
  1036.  
  1037.       case RP_SHORT_LEFT:    /* remove shortest match at start */
  1038.     for (p = param; p <= end; p++)
  1039.       {
  1040.         c = *p; *p = '\0';
  1041.         if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
  1042.           {
  1043.         *p = c;
  1044.         return (savestring (p));
  1045.           }
  1046.         *p = c;
  1047.       }
  1048.     break;
  1049.  
  1050.       case RP_LONG_RIGHT:    /* remove longest match at end */
  1051.     for (p = param; p <= end; p++)
  1052.       {
  1053.         if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
  1054.           {
  1055.         c = *p;
  1056.         *p = '\0';
  1057.         ret = savestring (param);
  1058.         *p = c;
  1059.         return (ret);
  1060.           }
  1061.       }
  1062.     break;
  1063.  
  1064.       case RP_SHORT_RIGHT:    /* remove shortest match at end */
  1065.     for (p = end; p >= param; p--)
  1066.       {
  1067.         if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
  1068.           {
  1069.         c = *p;
  1070.         *p = '\0';
  1071.         ret = savestring (param);
  1072.         *p = c;
  1073.         return (ret);
  1074.           }
  1075.       }
  1076.     break;
  1077.     }
  1078.   return (savestring (param));    /* no match, return original string */
  1079. }
  1080.  
  1081. /*******************************************
  1082.  *                       *
  1083.  *    Functions to expand WORD_DESCs       *
  1084.  *                       *
  1085.  *******************************************/
  1086.  
  1087. /* Expand WORD, performing word splitting on the result.  This does
  1088.    parameter expansion, command substitution, arithmetic expansion,
  1089.    word splitting, and quote removal. */
  1090.  
  1091. WORD_LIST *
  1092. expand_word (word, quoted)
  1093.      WORD_DESC *word;
  1094.      int quoted;
  1095. {
  1096.   WORD_LIST *word_list_split (), *expand_word_internal ();
  1097.   WORD_LIST *result, *tresult;
  1098.  
  1099.   tresult = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1100.   result = word_list_split (tresult);
  1101.   dispose_words (tresult);
  1102.   if (result)
  1103.     dequote_list (result);
  1104.   return (result);
  1105. }
  1106.  
  1107. /* Expand WORD, but do not perform word splitting on the result.  This
  1108.    does parameter expansion, command substitution, arithmetic expansion,
  1109.    and quote removal. */
  1110. WORD_LIST *
  1111. expand_word_no_split (word, quoted)
  1112.      WORD_DESC *word;
  1113.      int quoted;
  1114. {
  1115.   WORD_LIST *expand_word_internal ();
  1116.   WORD_LIST *result;
  1117.  
  1118.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1119.   if (result)
  1120.     dequote_list (result);
  1121.   return (result);
  1122. }
  1123.  
  1124. WORD_LIST *
  1125. expand_word_leave_quoted (word, quoted)
  1126.      WORD_DESC *word;
  1127.      int quoted;
  1128. {
  1129.   WORD_LIST *expand_word_internal (), *result;
  1130.  
  1131.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1132.   return (result);
  1133. }
  1134.  
  1135. /* Return the value of a positional parameter.  This handles values > 10. */
  1136. char *
  1137. get_dollar_var_value (ind)
  1138.      int ind;
  1139. {
  1140.   char *temp;
  1141.  
  1142.   if (ind < 10)
  1143.     {
  1144.       if (dollar_vars[ind])
  1145.     temp = savestring (dollar_vars[ind]);
  1146.       else
  1147.     temp = (char *)NULL;
  1148.     }
  1149.   else    /* We want something like ${11} */
  1150.     {
  1151.       WORD_LIST *p = rest_of_args;
  1152.  
  1153.       ind -= 10;
  1154.       while (p && ind--)
  1155.     p = p->next;
  1156.       if (p)
  1157.     temp = savestring (p->word->word);
  1158.       else
  1159.     temp = (char *)NULL;
  1160.     }
  1161.   return (temp);
  1162. }
  1163.  
  1164. /* Perform command substitution on STRING.  This returns a string,
  1165.    possibly quoted. */
  1166. static char *
  1167. command_substitute (string, quoted)
  1168.      char *string;
  1169.      int quoted;
  1170. {
  1171.   pid_t pid, old_pid;
  1172.   int fildes[2];
  1173.   char *istring = (char *)NULL;
  1174.   int istring_index, istring_size, c = 1;
  1175.   extern int interactive, last_command_exit_value;
  1176. #if defined(__OS2__)
  1177. HFILE localPipeIn,
  1178.         localPipeOut;
  1179. ULONG        bytesWritten,
  1180.         rc;
  1181. #endif
  1182.  
  1183.   istring_index = istring_size = 0;
  1184.  
  1185.   /* Don't fork () if there is no need to.  In the case of no command to
  1186.      run, just return NULL. */
  1187.   if (!string || !*string)
  1188.     return ((char *)NULL);
  1189.  
  1190.   /* Pipe the output of executing STRING into the current shell. */
  1191.   if (pipe (fildes) < 0)
  1192.     {
  1193.       report_error ("Can't make pipes for command substitution!");
  1194.       goto error_exit;
  1195.     }
  1196.       
  1197.   old_pid = last_made_pid;
  1198. #if defined (JOB_CONTROL)
  1199.   {
  1200.     pid_t old_pipeline_pgrp = pipeline_pgrp;    
  1201.  
  1202.     pipeline_pgrp = shell_pgrp;
  1203.     pid = make_child (savestring ("command substitution"), 0);
  1204.  
  1205.     stop_making_children ();
  1206.     pipeline_pgrp = old_pipeline_pgrp;
  1207.   }
  1208. #else   /* JOB_CONTROL */
  1209.  
  1210. #if defined(__EMX__)    
  1211.     localPipeIn = pipeReadHandle;
  1212.     localPipeOut = pipeWriteHandle;
  1213.     rc = DosCreatePipe(&pipeReadHandle, &pipeWriteHandle, 20);
  1214. #if defined(__DEBUG__)
  1215. DEBUG_OUT("command_substitute: pid=%d,localPipeIn=%d, localPipeOut=%d, \
  1216. pipeReadHandle=%d, pipeWriteHandle=%d\n", getpid(), localPipeIn, localPipeOut,
  1217. pipeReadHandle, pipeWriteHandle);
  1218. DEBUG_OUT("command_substitute: forking at line 1209 string=%s, myPid=%d\n",
  1219.  string, getpid());
  1220.         DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, 5, 0);
  1221. #endif
  1222.  
  1223. #endif
  1224.   pid = make_child (savestring ("command substitution"), 0);
  1225. #endif  /* JOB_CONTROL */
  1226.  
  1227.   if (pid < 0)
  1228.     {
  1229. #if defined(__EMX__)
  1230.     DosClose(pipeWriteHandle);
  1231.     DosClose(pipeReadHandle);
  1232.     pipeReadHandle = localPipeIn;
  1233.     pipeWriteHandle = localPipeOut;
  1234.     DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, -5, 0);
  1235. #endif
  1236.       report_error ("Can't make a child for command substitution!");
  1237.     error_exit:
  1238.       if (istring)
  1239.     free (istring);
  1240.       return ((char *)NULL);
  1241.     }
  1242.  
  1243.   if (pid == 0)
  1244.     {int        childLastPipeOut;
  1245.     int    result_code;
  1246.  
  1247. #if defined(__EMX__)
  1248.     DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, -5, 0);
  1249.     closeForkPipes(localPipeIn, localPipeOut);
  1250.     DosClose(pipeReadHandle);
  1251.         DosExitList(0x2000+EXLST_ADD, (PFNEXITLIST) childExitListProc);
  1252.         pipeReadHandle = 0;
  1253. #endif
  1254. #if defined (JOB_CONTROL)
  1255.       set_job_control (0);
  1256. #endif
  1257.       if (dup2 (fildes[1], 1) < 0)
  1258.     {
  1259.       extern int errno;
  1260.       report_error ("command_substitute: cannot duplicate pipe as fd 1: %s\n",
  1261.             strerror (errno));
  1262. #if defined(__EMX__)
  1263.         result_code = EXECUTION_FAILURE;
  1264. DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, +5, 0);
  1265.         rc = DosWrite(pipeWriteHandle, &result_code, 4, &bytesWritten);
  1266. #if defined(__DEBUG__)
  1267. DEBUG_OUT("command_substitute: (writting) pid=%d, pipeWriteHandle=%d, result_code=%d,
  1268.  rc=%d\n", getpid(), pipeWriteHandle, result_code, rc);
  1269. #endif
  1270.         DosClose(pipeWriteHandle);
  1271.         pipeWriteHandle = 0;
  1272. #endif
  1273.       exit (EXECUTION_FAILURE);
  1274.     }
  1275.       close (fildes[1]);
  1276.       /* If standard output is closed in the parent shell
  1277.      (such as after `exec >&-'), file descriptor 1 will be
  1278.      the lowest available file descriptor, and end up in
  1279.      fildes[0].  This can happen for stdin and stderr as well,
  1280.      but stdout is more important -- it will cause no output
  1281.      to be generated from this command. */
  1282.       if (fildes[0] > 2)
  1283.     close (fildes[0]);
  1284.       interactive = 0;
  1285.  
  1286.     childLastPipeOut = pipeWriteHandle;
  1287.       result_code = parse_and_execute (string, "command substitution");
  1288.     pipeWriteHandle = childLastPipeOut;
  1289. #if defined(__EMX__)
  1290. DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, +5, 0);
  1291.         rc = DosWrite(pipeWriteHandle, &result_code, 4, &bytesWritten);
  1292. #if defined(__DEBUG__)
  1293. DEBUG_OUT("command_substitute (writting) pid=%d, pipeWriteHandle=%d, result_code=%d,\
  1294.  rc=%d\n", getpid(), pipeWriteHandle, result_code, rc);
  1295. #endif
  1296.         DosClose(pipeWriteHandle);
  1297.     pipeWriteHandle = 0;
  1298. #endif
  1299.     exit(result_code);
  1300.     }            /* child */
  1301.   else
  1302.     {
  1303.       FILE *istream;
  1304.  
  1305.     
  1306.       istream = fdopen (fildes[0], "r");
  1307.  
  1308. #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
  1309.       close_pgrp_pipe ();
  1310. #endif /* JOB_CONTROL && PGRP_PIPE */
  1311.  
  1312.       close (fildes[1]);
  1313.  
  1314.       if (!istream)
  1315.     {
  1316.         DosClose(pipeReadHandle);
  1317.         DosClose(pipeWriteHandle);
  1318.         pipeReadHandle = localPipeIn;
  1319.         pipeWriteHandle = localPipeOut;
  1320.       report_error ("Can't reopen pipe to command substitution");
  1321.         DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, -5, 0);
  1322.       goto error_exit;
  1323.     }
  1324.  
  1325.       /* Read the output of the command through the pipe. */
  1326.       while (1)
  1327.     {
  1328. #if defined (USG) || (defined (_POSIX_VERSION) && defined (Ultrix))
  1329.       c = sysv_getc (istream);
  1330. #else
  1331.       c = getc (istream);
  1332. #endif
  1333.  
  1334.       if (c == EOF)
  1335.         break;
  1336.  
  1337.       /* Add the character to ISTRING. */
  1338.       while (istring_index + 1 >= istring_size)
  1339.         istring = (char *) xrealloc
  1340.           (istring, istring_size += DEFAULT_ARRAY_SIZE);
  1341.  
  1342.       if (quoted)
  1343.         istring[istring_index++] = QUOTE_CHAR (c);
  1344.       else
  1345.         istring[istring_index++] = c;
  1346.  
  1347.       istring[istring_index] = '\0';
  1348.     }
  1349.  
  1350.       fclose (istream);
  1351.       close (fildes[0]);
  1352.  
  1353.     DosClose(pipeWriteHandle);
  1354.     pipeWriteHandle = 0;
  1355.       last_command_exit_value = wait_for (pid);
  1356.     DosSetPriority(PRTYS_PROCESS, PRTYC_NOCHANGE, -5, 0);
  1357.     pipeReadHandle = localPipeIn;
  1358.     pipeWriteHandle = localPipeOut;
  1359.       last_command_subst_pid = pid;
  1360.       last_made_pid = old_pid;
  1361.  
  1362. #if defined (JOB_CONTROL)
  1363.       /* If last_command_exit_value > 128, then the substituted command
  1364.      was terminated by a signal.  If that signal was SIGINT, then send
  1365.      SIGINT to ourselves.  This will break out of loops, for instance. */
  1366.       if (last_command_exit_value == (128 + SIGINT))
  1367.     kill (getpid (), SIGINT);
  1368.  
  1369.       /* wait_for gives the terminal back to shell_pgrp.  If some other
  1370.          process group should have it, give it away to that group here. */
  1371.       if (pipeline_pgrp != (pid_t)0)
  1372.     give_terminal_to (pipeline_pgrp);
  1373. #endif /* JOB_CONTROL */
  1374.  
  1375.       /* If we read no output, just return now and save ourselves some
  1376.      trouble. */
  1377.       if (istring_index == 0)
  1378.     goto error_exit;
  1379.  
  1380.       /* Strip trailing newlines from the output of the command. */
  1381.       if (quoted)
  1382.     {
  1383.       while (istring_index > 0 &&
  1384.           DEQUOTE_CHAR (istring[istring_index - 1]) == '\n')
  1385.         --istring_index;
  1386.  
  1387.       istring[istring_index] = '\0';
  1388.     }
  1389.       else
  1390.     {
  1391.       strip_trailing (istring, 1);
  1392.       istring_index = strlen (istring);
  1393.     }
  1394.  
  1395.       return (istring);
  1396.     }
  1397. }
  1398.  
  1399. /********************************************************
  1400.  *                            *
  1401.  *    Utility functions for parameter expansion    *
  1402.  *                            *
  1403.  ********************************************************/
  1404.  
  1405. /* Handle removing a pattern from a string as a result of ${name%[%]value}
  1406.    or ${name#[#]value}. */
  1407. static char *
  1408. parameter_brace_remove_pattern (value, temp, c)
  1409.      char *value, *temp;
  1410.      int c;
  1411. {
  1412.   int pattern_specifier;
  1413.   WORD_LIST *l;
  1414.   char *pattern, *t;
  1415.  
  1416.   if (c == '#')
  1417.     {
  1418.       if (*value == '#')
  1419.     {
  1420.       value++;
  1421.       pattern_specifier = RP_LONG_LEFT;
  1422.     }
  1423.       else
  1424.     pattern_specifier = RP_SHORT_LEFT;
  1425.     }
  1426.   else    /* c == '%' */
  1427.     {
  1428.       if (*value == '%')
  1429.     {
  1430.       value++;
  1431.       pattern_specifier = RP_LONG_RIGHT;
  1432.     }
  1433.       else
  1434.     pattern_specifier = RP_SHORT_RIGHT;
  1435.     }
  1436.  
  1437.   l = expand_string (value, 0);
  1438.   pattern = (char *)string_list (l);
  1439.   dispose_words (l);
  1440.   t = remove_pattern (temp, pattern, pattern_specifier);
  1441.   free (pattern);
  1442.   return (t);
  1443. }
  1444.  
  1445. /* Parameter expand NAME, and return a new string which is the expansion,
  1446.    or NULL if there was no expansion.
  1447.    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
  1448.    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
  1449.    NAME was found inside of a double-quoted expression. */
  1450. static char *
  1451. parameter_brace_expand_word (name, var_is_special, quoted)
  1452.      char *name;
  1453.      int var_is_special, quoted;
  1454. {
  1455.   char *temp = (char *)NULL;
  1456.  
  1457.   /* Handle multiple digit arguments, as in ${11}. */
  1458.   if (digit (*name))
  1459.     {
  1460.       int arg_index = atoi (name);
  1461.  
  1462.       temp = get_dollar_var_value (arg_index);
  1463.     }
  1464.   else if (var_is_special)      /* ${@} */
  1465.     {
  1466.       char *tt;
  1467.       WORD_LIST *l;
  1468.  
  1469.       tt = (char *)alloca (2 + strlen (name));
  1470.       tt[0] = '$'; tt[1] = '\0';
  1471.       strcat (tt, name);
  1472.       l = expand_string_leave_quoted (tt, quoted);
  1473.       temp = string_list (l);
  1474.       dispose_words (l);
  1475.     }
  1476.   else
  1477.     {
  1478.       SHELL_VAR *var = find_variable (name);
  1479.  
  1480.       if (var && !invisible_p (var) && (temp = value_cell (var)))
  1481.     temp = savestring (temp);
  1482.     }
  1483.   return (temp);
  1484. }
  1485.  
  1486. /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
  1487.    depending on the value of C, the separating character.  C can be one of
  1488.    "-", "+", or "=". */
  1489. static char *
  1490. parameter_brace_expand_rhs (name, value, c, quoted)
  1491.      char *name, *value;
  1492.      int c;
  1493. {
  1494.   extern char *tilde_expand ();
  1495.   WORD_LIST *l;
  1496.   char *t, *t1, *temp;
  1497.  
  1498.   if (value[0] == '~' ||
  1499.       (index (value, '~') && unquoted_substring ("=~", value)))
  1500.     temp = tilde_expand (value);
  1501.   else
  1502.     temp = savestring (value);
  1503.  
  1504.   l = expand_string_leave_quoted (temp, quoted);
  1505.   free (temp);
  1506.  
  1507.   temp = (char *)string_list (l);
  1508.   dispose_words (l);
  1509.  
  1510.   if (c == '-' || c == '+')
  1511.     return (temp);
  1512.  
  1513.   /* c == '=' */
  1514.   if (temp)
  1515.     t = savestring (temp);
  1516.   else
  1517.     t = savestring ("");
  1518.   t1 = dequote_string (t);
  1519.   free (t);
  1520.   t = t1;
  1521.   bind_variable (name, t);
  1522.   free (t);
  1523.   return (temp);
  1524. }
  1525.  
  1526. /* Deal with the right hand side of a ${name:?value} expansion in the case
  1527.    that NAME is null or not set.  If VALUE is non-null it is expanded and
  1528.    used as the error message to print, otherwise a standard message is
  1529.    printed. */
  1530. static void
  1531. parameter_brace_expand_error (name, value)
  1532.      char *name, *value;
  1533. {
  1534.   extern int interactive;
  1535.  
  1536.   if (value && *value)
  1537.     {
  1538.       WORD_LIST *l = expand_string (value, 0);
  1539.       char *temp1 =  string_list (l);
  1540.       fprintf (stderr, "%s: %s\n", name, temp1 ? temp1 : value);
  1541.       if (temp1)
  1542.     free (temp1);
  1543.       dispose_words (l);
  1544.     }
  1545.   else
  1546.     report_error ("%s: parameter null or not set", name);
  1547.  
  1548.   /* Free the data we have allocated during this expansion, since we
  1549.      are about to longjmp out. */
  1550.   free (name);
  1551.   if (value)
  1552.     free (value);
  1553.  
  1554.   if (!interactive)
  1555.     longjmp (top_level, FORCE_EOF);
  1556.   else
  1557.     longjmp (top_level, DISCARD);
  1558. }
  1559.  
  1560. /* Handle the parameter brace expansion that requires us to return the
  1561.    length of a parameter. */
  1562. static int
  1563. parameter_brace_expand_length (name)
  1564.      char *name;
  1565. {
  1566.   char *t;
  1567.   int number = 0;
  1568.  
  1569.   if (name[1] == '\0')            /* ${#} */
  1570.     {
  1571.       WORD_LIST *l = list_rest_of_args ();
  1572.       number = list_length (l);
  1573.       dispose_words (l);
  1574.     }
  1575.   else if (name[1] != '*' && name[1] != '@')
  1576.     {
  1577.       number = 0;
  1578.  
  1579.       if (digit (name[1]))        /* ${#1} */
  1580.     {
  1581.       if (t = get_dollar_var_value (atoi (&name[1])))
  1582.         {
  1583.           number = strlen (t);
  1584.           free (t);
  1585.         }
  1586.     }
  1587.       else                /* ${#PS1} */
  1588.     {
  1589.       WORD_LIST *list;
  1590.       char *newname;
  1591.  
  1592.       newname = savestring (name);
  1593.       newname[0] = '$';
  1594.       list = expand_string (newname, 0);
  1595.       t = string_list (list);
  1596.       free (newname);
  1597.       dispose_words (list);
  1598.  
  1599.       if (t)
  1600.         number = strlen (t);
  1601.     }
  1602.     }
  1603.   else                    /* ${#@} and ${#*} */
  1604.     {
  1605.       if (t = string_rest_of_args (1))
  1606.     {
  1607.       number = strlen (t);
  1608.       free (t);
  1609.     }
  1610.     }
  1611.   return (number);
  1612. }
  1613.  
  1614. /* Make a word list which is the parameter and variable expansion,
  1615.    command substitution, arithmetic substitution, and quote removed
  1616.    expansion of WORD.  Return a pointer to a WORD_LIST which is the
  1617.    result of the expansion.  If WORD contains a null word, the word
  1618.    list returned is also null.
  1619.  
  1620.    QUOTED, when non-zero specifies that the text of WORD is treated
  1621.    as if it were surrounded by double quotes.
  1622.    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
  1623.    they point to an integer value which receives information about expansion.
  1624.    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
  1625.    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
  1626.    else zero.
  1627.  
  1628.    This only does word splitting in the case of $@ expansion.  In that
  1629.    case, we split on ' '. */
  1630. WORD_LIST *
  1631. expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
  1632.      WORD_DESC *word;
  1633.      int quoted;
  1634.      int *contains_dollar_at;
  1635.      int *expanded_something;
  1636. {
  1637.   extern char *itos ();
  1638.   extern int last_command_exit_value;
  1639.  
  1640.   /* The thing that we finally output. */
  1641.   WORD_LIST *result = (WORD_LIST *)NULL;
  1642.  
  1643.   /* The intermediate string that we build while expanding. */
  1644.   char *istring = (char *)xmalloc (DEFAULT_ARRAY_SIZE);
  1645.  
  1646.   /* The current size of the above object. */
  1647.   int istring_size = DEFAULT_ARRAY_SIZE;
  1648.  
  1649.   /* Index into ISTRING. */
  1650.   int istring_index = 0;
  1651.  
  1652.   /* Temporary string storage. */
  1653.   char *temp = (char *)NULL;
  1654.  
  1655.   /* The text of WORD. */
  1656.   register char *string = word->word;
  1657.  
  1658.   /* The index into STRING. */
  1659.   register int sindex = 0;
  1660.  
  1661.   /* This gets 1 if we see a $@ while quoted. */
  1662.   int quoted_dollar_at = 0;
  1663.  
  1664.   /* This gets 1 if we are to treat backslashes as if we are within double
  1665.      quotes, but not otherwise behave as if the word is quoted.  This is
  1666.      used for things like expansion of patterns in case statement pattern
  1667.      lists.  This is a private variable, but the incoming value of
  1668.      Q_KEEP_BACKSLASH is passed to recursive invocations of this function. */
  1669.   int preserve_backslashes = 0;
  1670.  
  1671.   register int c;        /* Current character. */
  1672.   int number;            /* Temporary number value. */
  1673.   int t_index;            /* For calls to string_extract_xxx. */
  1674.   extern int interactive;
  1675.   char *command_subst_result;    /* For calls to command_substitute (). */
  1676.  
  1677.   istring[0] = '\0';
  1678.  
  1679.   if (!string) goto final_exit;
  1680.  
  1681.   if (quoted & Q_KEEP_BACKSLASH)
  1682.     {
  1683.       preserve_backslashes = 1;
  1684.       quoted &= ~Q_KEEP_BACKSLASH;
  1685.     }
  1686.  
  1687.   if (contains_dollar_at)
  1688.     *contains_dollar_at = 0;
  1689.  
  1690.   /* Begin the expansion. */
  1691.  
  1692.   for (;;) {
  1693.  
  1694.     c = string[sindex];
  1695.  
  1696.     switch (c) {        /* Case on toplevel character. */
  1697.  
  1698.     case '\0':
  1699.       goto finished_with_string;
  1700.  
  1701.     case '$':
  1702.  
  1703.       if (expanded_something)
  1704.     *expanded_something = 1;
  1705.  
  1706.       c = string[++sindex];
  1707.  
  1708.       /* Do simple cases first. Switch on what follows '$'. */
  1709.       switch (c)
  1710.     {
  1711.       /* $0 .. $9? */
  1712.     case '0':
  1713.     case '1':
  1714.     case '2':
  1715.     case '3':
  1716.     case '4':
  1717.     case '5':
  1718.     case '6':
  1719.     case '7':
  1720.     case '8':
  1721.     case '9':
  1722.       if (dollar_vars[digit_value (c)])
  1723.         temp = savestring (dollar_vars[digit_value (c)]);
  1724.       else
  1725.         temp = (char *)NULL;
  1726.       goto dollar_add_string;
  1727.  
  1728.     case '$':        /* $$ -- pid of the invoking shell. */
  1729.       {
  1730.         extern int dollar_dollar_pid;
  1731.         number = dollar_dollar_pid;
  1732.       }
  1733.     add_number:
  1734.       temp = itos (number);
  1735.     dollar_add_string:
  1736.       if (string[sindex]) sindex++;
  1737.  
  1738.       /* Add TEMP to ISTRING. */
  1739.     add_string:
  1740.       istring =
  1741.         sub_append_string (temp, istring, &istring_index, &istring_size);
  1742.       break;
  1743.  
  1744.       /* $# -- number of positional parameters. */
  1745.     case '#':
  1746.       {
  1747.         WORD_LIST *list = list_rest_of_args ();
  1748.         number = list_length (list);
  1749.         dispose_words (list);
  1750.         goto add_number;
  1751.       }
  1752.  
  1753.       /* $? -- return value of the last synchronous command. */
  1754.     case '?':
  1755.       number = last_command_exit_value;
  1756.       goto add_number;
  1757.  
  1758.       /* $- -- flags supplied to the shell on invocation or by `set'. */
  1759.     case '-':
  1760.  
  1761.       temp = (char *)which_set_flags ();
  1762.       goto dollar_add_string;
  1763.  
  1764.       /* $! -- Pid of the last asynchronous command. */
  1765.     case '!':
  1766.       {
  1767.         number = (int)last_asynchronous_pid;
  1768.  
  1769.         /* If no asynchronous pids have been created, echo nothing. */
  1770.         if (number == (int)NO_PID)
  1771.           {
  1772.         if (string[sindex])
  1773.           sindex++;
  1774.         if (expanded_something)
  1775.           *expanded_something = 0;
  1776.         break;
  1777.           }
  1778.         goto add_number;
  1779.       }
  1780.  
  1781.       /* The only difference between this and $@ is when the
  1782.          arg is quoted. */
  1783.     case '*':        /* `$*' */
  1784.       temp = string_rest_of_args (quoted);
  1785.  
  1786.       /* In the case of a quoted string, quote the entire arg-list.
  1787.          "$1 $2 $3". */
  1788.       if (quoted && temp)
  1789.         {
  1790.           char *james_brown = temp;
  1791.           temp = quote_string (temp);
  1792.           free (james_brown);
  1793.         }
  1794.       goto dollar_add_string;
  1795.  
  1796.       /* When we have "$@" what we want is "$1" "$2" "$3" ... This
  1797.          means that we have to turn quoting off after we split into
  1798.          the individually quoted arguments so that the final split
  1799.          on the first character of $IFS is still done.  */
  1800.     case '@':        /* `$@' */
  1801.       {
  1802.         WORD_LIST *tlist = list_rest_of_args ();
  1803.         if (quoted && tlist)
  1804.           quote_list (tlist);
  1805.  
  1806.         /* We want to flag the fact that we saw this.  We can't turn off
  1807.            quoting entirely, because other characters in the string might
  1808.            need it (consider "\"$@\""), but we need some way to signal
  1809.            that the final split on the first character of $IFS should be
  1810.            done, even though QUOTED is 1. */
  1811.         if (quoted)
  1812.           quoted_dollar_at = 1;
  1813.         if (contains_dollar_at)
  1814.           *contains_dollar_at = 1;
  1815.         temp = string_list (tlist);
  1816.         goto dollar_add_string;
  1817.       }
  1818.  
  1819.       /* ${[#]name[[:]#[#]%[%]-=?+[word]]} */
  1820.     case '{':
  1821.       {
  1822.         int check_nullness = 0;
  1823.         int var_is_set = 0;
  1824.         int var_is_null = 0;
  1825.         int var_is_special = 0;
  1826.         char *name, *value;
  1827.  
  1828.         sindex++;
  1829.         t_index = sindex;
  1830.         name = string_extract (string, &t_index, "#%:-=?+}");
  1831.  
  1832.         /* If the name really consists of a special variable, then
  1833.            make sure that we have the entire name. */
  1834.         if (sindex == t_index &&
  1835.         (string[sindex] == '-' ||
  1836.          string[sindex] == '?' ||
  1837.          string[sindex] == '#'))
  1838.           {
  1839.         char *tt;
  1840.         t_index++;
  1841.         free (name);
  1842.         tt = (string_extract (string, &t_index, "#%:-=?+}"));
  1843.         name = (char *)xmalloc (2 + (strlen (tt)));
  1844.         *name = string[sindex];
  1845.         strcpy (name + 1, tt);
  1846.         free (tt);
  1847.           }
  1848.         sindex = t_index;
  1849.  
  1850.         /* Find out what character ended the variable name.  Then
  1851.            do the appropriate thing. */
  1852.  
  1853.         if (c = string[sindex])
  1854.           sindex++;
  1855.  
  1856.         if (c == ':')
  1857.           {
  1858.         check_nullness++;
  1859.         if (c = string[sindex])
  1860.           sindex++;
  1861.           }
  1862.  
  1863.         /* Determine the value of this variable. */
  1864.         if (digit (*name) ||
  1865.         (strlen (name) == 1 && member (*name, "#-?$!@*")))
  1866.           var_is_special++;
  1867.  
  1868.         /* Check for special expansion things. */
  1869.         if (*name == '#')
  1870.           {
  1871.         /* Handle ${#-} and ${#?}.  They return the lengths of
  1872.            $- and $?, respectively. */
  1873.         if (string[sindex] == '}' &&
  1874.             !name[1] &&
  1875.             !check_nullness &&
  1876.             (c == '-' || c == '?'))
  1877.           {
  1878.             char *s;
  1879.  
  1880.             free (name);
  1881.  
  1882.             if (c == '-')
  1883.               s = (char *)which_set_flags ();
  1884.             else
  1885.               s = itos (last_command_exit_value);
  1886.  
  1887.             number = s ? strlen (s) : 0;
  1888.             if (s)
  1889.               free (s);
  1890.             goto add_number;
  1891.           }
  1892.  
  1893.         /* Don't allow things like ${#:-foo} to go by; they are
  1894.            errors.  If we are not pointing at the character just
  1895.            after the closing brace, then we haven't gotten all of
  1896.            the name.  Since it begins with a special character,
  1897.            this is a bad substitution.  Explicitly check for ${#:},
  1898.            which the rules do not catch. */
  1899.         if (string[sindex - 1] != '}' || member (c, "?-=+") ||
  1900.             (string[sindex - 1] == '}' && !name[1] && c == '}' &&
  1901.              check_nullness))
  1902.           {
  1903.             free (name);
  1904.             name = string;
  1905.             goto bad_substitution;
  1906.           }
  1907.  
  1908.         number = parameter_brace_expand_length (name);
  1909.         /* We are pointing one character after the brace which
  1910.            closes this expression.  Since the code at add_number
  1911.            increments SINDEX, we back up a single character here. */
  1912.         sindex--;
  1913.         goto add_number;
  1914.           }
  1915.  
  1916.         /* ${@} is identical to $@. */
  1917.         if (name[0] == '@' && name[1] == '\0')
  1918.           {
  1919.         if (quoted)
  1920.           quoted_dollar_at = 1;
  1921.  
  1922.         if (contains_dollar_at)
  1923.           *contains_dollar_at = 1;
  1924.           }
  1925.  
  1926.         temp = parameter_brace_expand_word (name, var_is_special, quoted);
  1927.  
  1928.         if (temp)
  1929.           var_is_set++;
  1930.  
  1931.         if (!var_is_set || !temp || !*temp)
  1932.           var_is_null++;
  1933.  
  1934.         if (!check_nullness)
  1935.           var_is_null = 0;
  1936.  
  1937.         /* Get the rest of the stuff inside the braces. */
  1938.         if (c && c != '}')
  1939.           {
  1940.         /* Scan forward searching for last `{'.  This is a hack,
  1941.            it will always be a hack, and it always has been a hack. */
  1942.         t_index = sindex;
  1943.         value = extract_delimited_string (string, &t_index,
  1944.                           "{", (char *)NULL, "}");
  1945.         sindex = t_index;
  1946.  
  1947.         if (string[sindex] == '}')
  1948.           sindex++;
  1949.         else
  1950.           {
  1951.             if (value)
  1952.               free (value);
  1953.  
  1954.             free (name);
  1955.             name = string;
  1956.             goto bad_substitution;
  1957.           }
  1958.           }
  1959.         else
  1960.           value = (char *)NULL;
  1961.  
  1962.         /* Do the right thing based on which character ended the variable
  1963.            name. */
  1964.         switch (c)
  1965.           {
  1966.           case '\0':
  1967.           bad_substitution:
  1968.         report_error ("%s: bad substitution", name ? name : "??");
  1969.         free (name);
  1970.         longjmp (top_level, DISCARD);
  1971.  
  1972.           case '}':
  1973.         break;
  1974.  
  1975.           case '#':        /* ${param#[#]pattern} */
  1976.           case '%':        /* ${param%[%]pattern} */
  1977.         {
  1978.           char *t;
  1979.           if (!value || !*value || !temp || !*temp)
  1980.             break;
  1981.           t = parameter_brace_remove_pattern (value, temp, c);
  1982.           free (temp);
  1983.           free (value);
  1984.           temp = t;
  1985.         }
  1986.         break;
  1987.  
  1988.           case '-':
  1989.           case '=':
  1990.           case '?':
  1991.           case '+':
  1992.         if (var_is_set && !var_is_null)
  1993.           {
  1994.             /* We don't want the value of the named variable for
  1995.                anything, just the value of the right hand side. */
  1996.             if (c == '+')
  1997.               {
  1998.             if (temp)
  1999.               free (temp);
  2000.             if (value)
  2001.               temp = parameter_brace_expand_rhs (name, value, c, quoted);
  2002.             else
  2003.               temp = (char *)NULL;
  2004.               }
  2005.             /* Otherwise do nothing.  Just use the value in temp. */
  2006.           }
  2007.         else        /* var not set or var is null */
  2008.           {
  2009.             if (temp)
  2010.               free (temp);
  2011.             temp = (char *)NULL;
  2012.             if (c == '=' && var_is_special)
  2013.               {
  2014.             report_error ("$%s: cannot assign in this way", name);
  2015.             free (name);
  2016.             free (value);
  2017.             longjmp (top_level, DISCARD);
  2018.               }
  2019.             else if (c == '?')
  2020.               parameter_brace_expand_error (name, value);
  2021.             else if (c != '+')
  2022.               temp =
  2023.             parameter_brace_expand_rhs (name, value, c, quoted);
  2024.             free (value);
  2025.           }
  2026.         break;
  2027.           }            /* end case on closing character. */
  2028.         free (name);
  2029.         goto add_string;
  2030.       }            /* end case '{' */
  2031.       /* break; */
  2032.  
  2033.     case '(':        /* Do command or arithmetic substitution. */
  2034.       /* We have to extract the contents of this paren substitution. */
  2035.       {
  2036.         char *extract_command_subst ();
  2037.         int old_index = ++sindex;
  2038.  
  2039.         temp = extract_command_subst (string, &old_index);
  2040.         sindex = old_index;
  2041.  
  2042.         /* For the Posix.2-style $(( )) form of arithmetic substitution,
  2043.            extract the expression and pass it to the evaluator. */
  2044.         if (temp && *temp == '(')
  2045.           {
  2046.         char *t = temp + 1;
  2047.         int last = strlen (t) - 1;
  2048.         extern long evalexp ();
  2049.  
  2050.         if (t[last] != ')')
  2051.           {
  2052.             report_error ("%s: bad arithmetic substitution", temp);
  2053.             free (temp);
  2054.             /* XXX - these are mem leaks */
  2055.             longjmp (top_level, DISCARD);
  2056.           }
  2057.  
  2058.         /* Cut off ending `)' */
  2059.         t[last] = '\0';
  2060.  
  2061.         number = (int)evalexp (t);
  2062.         free (temp);
  2063.         goto add_number;
  2064.           }
  2065.  
  2066.         goto handle_command_substitution;
  2067.       }
  2068.  
  2069.       /* Do straight arithmetic substitution. */
  2070.     case '[':
  2071.       /* We have to extract the contents of this
  2072.          arithmetic substitution. */
  2073.       {
  2074.         char *extract_arithmetic_subst (), *t;
  2075.         int old_index = ++sindex;
  2076.         WORD_LIST *l;
  2077.         extern long evalexp ();
  2078.         extern char *this_command_name;
  2079.  
  2080.         temp = extract_arithmetic_subst (string, &old_index);
  2081.         sindex = old_index;
  2082.  
  2083.         /* Do initial variable expansion. */
  2084.         l = expand_string (temp, 1);
  2085.         t = string_list (l);
  2086.         dispose_words (l);
  2087.  
  2088.         /* No error messages. */
  2089.         this_command_name = (char *)NULL;
  2090.         number = (int)evalexp (t);
  2091.         free (t);
  2092.  
  2093.         goto add_number;
  2094.       }
  2095.  
  2096.     default:
  2097.       {
  2098.         /* Find the variable in VARIABLE_LIST. */
  2099.         int old_index = sindex;
  2100.         char *name;
  2101.         SHELL_VAR *var;
  2102.  
  2103.         temp = (char *)NULL;
  2104.  
  2105.         for (;
  2106.          (c = string[sindex]) &&
  2107.          (isletter (c) || digit (c) || c == '_');
  2108.          sindex++);
  2109.         name = (char *)substring (string, old_index, sindex);
  2110.  
  2111.         /* If this isn't a variable name, then just output the `$'. */
  2112.         if (!name || !*name)
  2113.           {
  2114.         free (name);
  2115.         temp = savestring ("$");
  2116.         if (expanded_something)
  2117.           *expanded_something = 0;
  2118.         goto add_string;
  2119.           }
  2120.  
  2121.         /* If the variable exists, return its value cell. */
  2122.         var = find_variable (name);
  2123.  
  2124.         if (var && !invisible_p (var) && value_cell (var))
  2125.           {
  2126.         temp = savestring (value_cell (var));
  2127.         free (name);
  2128.         goto add_string;
  2129.           }
  2130.         else
  2131.           temp = (char *)NULL;
  2132.  
  2133.         if (unbound_vars_is_error)
  2134.           report_error ("%s: unbound variable", name);
  2135.         else
  2136.           goto add_string;
  2137.  
  2138.         free (name);
  2139.         longjmp (top_level, DISCARD);
  2140.       }
  2141.     }
  2142.       break;            /* End case '$': */
  2143.  
  2144.     case '`':            /* Backquoted command substitution. */
  2145.       {
  2146.     sindex++;
  2147.  
  2148.     if (expanded_something)
  2149.       *expanded_something = 1;
  2150.  
  2151.     t_index = sindex;
  2152.     temp = string_extract (string, &t_index, "`");
  2153.     sindex = t_index;
  2154.     de_backslash (temp);
  2155.  
  2156.       handle_command_substitution:
  2157.     command_subst_result = command_substitute (temp, quoted);
  2158.  
  2159.     if (temp)
  2160.       free (temp);
  2161.  
  2162.     temp = command_subst_result;
  2163.  
  2164.     if (string[sindex])
  2165.       sindex++;
  2166.  
  2167.     goto add_string;
  2168.       }
  2169.  
  2170.     case '\\':
  2171.       if (string[sindex + 1] == '\n')
  2172.     {
  2173.       sindex += 2;
  2174.       continue;
  2175.     }
  2176.       else
  2177.     {
  2178.       char *slashify_chars = "";
  2179.  
  2180.       c = string[++sindex];
  2181.  
  2182.       if (quoted == Q_HERE_DOCUMENT)
  2183.         slashify_chars = slashify_in_here_document;
  2184.       else if (quoted == Q_DOUBLE_QUOTES)
  2185.         slashify_chars = slashify_in_quotes;
  2186.  
  2187.       if (preserve_backslashes || (quoted && !member (c, slashify_chars)))
  2188.         {
  2189.           temp = (char *)xmalloc (3);
  2190.           temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
  2191.           if (c)
  2192.         sindex++;
  2193.           goto add_string;
  2194.         }
  2195.       else
  2196.         {
  2197.           /* This character is quoted, so add it in quoted mode. */
  2198.           c = QUOTE_CHAR (c);
  2199.           goto add_character;
  2200.         }
  2201.     }
  2202.  
  2203.     case '"':
  2204.       if (quoted)
  2205.     goto add_character;
  2206.       sindex++;
  2207.       {
  2208.     WORD_LIST *tresult = (WORD_LIST *)NULL;
  2209.  
  2210.     t_index = sindex;
  2211.     temp = string_extract_double_quoted (string, &t_index);
  2212.     sindex = t_index;
  2213.  
  2214.     if (string[sindex])
  2215.       sindex++;
  2216.  
  2217.     if (temp && *temp)
  2218.       {
  2219.         int dollar_at_flag;
  2220.         int quoting_flags = Q_DOUBLE_QUOTES;
  2221.         WORD_DESC *temp_word = make_word (temp);
  2222.  
  2223.         free (temp);
  2224.  
  2225.         if (preserve_backslashes)
  2226.           quoting_flags |= Q_KEEP_BACKSLASH;
  2227.         tresult = expand_word_internal (temp_word, quoting_flags,
  2228.                         &dollar_at_flag, (int *)NULL);
  2229.  
  2230.         dispose_word (temp_word);
  2231.  
  2232.         if (!tresult && dollar_at_flag)
  2233.           break;
  2234.         /* If we get "$@", we know we have expanded something, so we
  2235.            need to remember it for the final split on $IFS.  This is
  2236.            a special case; it's the only case where a quoted string
  2237.            can expand into more than one word.  It's going to come back
  2238.            from the above call to expand_word_internal as a list with
  2239.            a single word, in which all characters are quoted and
  2240.            separated by blanks.  What we want to do is to turn it back
  2241.            into a list for the next piece of code. */
  2242.         dequote_list (tresult);
  2243.         if (dollar_at_flag)
  2244.           quoted_dollar_at++;
  2245.         if (expanded_something)
  2246.           *expanded_something = 1;
  2247.       }
  2248.     else
  2249.       {
  2250.         /* What we have is "".  This is a minor optimization. */
  2251.         free (temp);
  2252.         tresult = (WORD_LIST *)NULL;
  2253.       }
  2254.  
  2255.     /* The code above *might* return a list (consider the case of "$@",
  2256.        where it returns "$1", "$2", etc.).  We can't throw away the rest
  2257.        of the list, and we have to make sure each word gets added as
  2258.        quoted.  We test on tresult->next:  if it is non-NULL, we quote
  2259.        the whole list, save it to a string with string_list, and add that
  2260.        string. We don't need to quote the results of this (and it would be
  2261.        wrong, since that would quote the separators as well), so we go
  2262.        directly to add_string. */
  2263.     if (tresult)
  2264.       {
  2265.         if (tresult->next)
  2266.           {
  2267.         quote_list (tresult);
  2268.         temp = string_list (tresult);
  2269.         dispose_words (tresult);
  2270.         goto add_string;
  2271.           }
  2272.         else
  2273.           {
  2274.         temp = savestring (tresult->word->word);
  2275.         dispose_words (tresult);
  2276.           }
  2277.       }
  2278.     else
  2279.       temp = (char *)NULL;
  2280.  
  2281.       add_quoted_string:
  2282.  
  2283.     if (temp)
  2284.       {
  2285.         char *t = temp;
  2286.         temp = quote_string (temp);
  2287.         free (t);
  2288.       }
  2289.     else
  2290.       {
  2291.         /* Add NULL arg. */
  2292.         temp = savestring (" ");
  2293.         temp[0] = (unsigned char)QUOTE_CHAR ('\0');
  2294.       }
  2295.     goto add_string;
  2296.       }
  2297.       /* break; */
  2298.  
  2299.     case '\'':
  2300.       {
  2301.     if (!quoted)
  2302.       {
  2303.         sindex++;
  2304.  
  2305.         t_index = sindex;
  2306.         temp = string_extract_verbatim (string, &t_index, "'");
  2307.         sindex = t_index;
  2308.  
  2309.         if (string[sindex])
  2310.           sindex++;
  2311.  
  2312.         if (!*temp)
  2313.           {
  2314.         free (temp);
  2315.         temp = (char *)NULL;
  2316.           }
  2317.  
  2318.         goto add_quoted_string;
  2319.       }
  2320.     else
  2321.       goto add_character;
  2322.  
  2323.     break;
  2324.       }
  2325.  
  2326.     default:
  2327.  
  2328.       /* This is the fix for " $@ " */
  2329.       if (quoted)
  2330.     c = QUOTE_CHAR (c);
  2331.  
  2332. add_character:
  2333.       while (istring_index + 1 >= istring_size)
  2334.     istring = (char *)
  2335.       xrealloc (istring, istring_size += DEFAULT_ARRAY_SIZE);
  2336.       istring[istring_index++] = c;
  2337.       istring[istring_index] = '\0';
  2338.  
  2339.       /* Next character. */
  2340.       sindex++;
  2341.     }
  2342.   }
  2343.  
  2344. finished_with_string:
  2345. final_exit:
  2346.   /* OK, we're ready to return.  If we have a quoted string, and
  2347.      quoted_dollar_at is not set, we do no splitting at all; otherwise
  2348.      we split on ' '.  The routines that call this will handle what to
  2349.      do if nothing has been expanded. */
  2350.   if (istring)
  2351.     {
  2352.       WORD_LIST *temp_list;
  2353.  
  2354.       if (quoted_dollar_at)
  2355.     temp_list = list_string (istring, " ", quoted);
  2356.       else if (*istring)
  2357.     {
  2358.       temp_list = make_word_list (make_word (istring), (WORD_LIST *)NULL);
  2359.       temp_list->word->quoted = quoted;
  2360.     }
  2361.       else
  2362.     temp_list = (WORD_LIST *)NULL;
  2363.       free (istring);
  2364.       result = (WORD_LIST *)list_append (reverse_list (result), temp_list);
  2365.     }
  2366.   else
  2367.     result = (WORD_LIST *)NULL;
  2368.  
  2369.   return (result);
  2370. }
  2371.  
  2372. /* **************************************************************** */
  2373. /*                                                                  */
  2374. /*              Functions for Quote Removal                */
  2375. /*                                                                  */
  2376. /* **************************************************************** */
  2377.  
  2378. /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
  2379.    backslash quoting rules for within double quotes. */
  2380. char *
  2381. string_quote_removal (string, quoted)
  2382.      char *string;
  2383.      int quoted;
  2384. {
  2385.   char *r, *result_string, *temp, *temp1;
  2386.   int sindex, tindex, c;
  2387.  
  2388.   /* The result can be no longer than the original string. */
  2389.   r = result_string = xmalloc (strlen (string) + 1);
  2390.   sindex = 0;
  2391.  
  2392.   for (;;)
  2393.     {
  2394.       c = string[sindex];
  2395.       if (c == '\0')
  2396.     break;
  2397.  
  2398.       switch (c)
  2399.     {
  2400.       case '\\':
  2401.         c = string[++sindex];
  2402.         if (quoted && !member (c, slashify_in_quotes))
  2403.           {
  2404.         *r++ = '\\';
  2405.         *r++ = c;
  2406.           }
  2407.         else
  2408.           *r++ = c;
  2409.  
  2410.         sindex++;
  2411.         break;
  2412.       
  2413.       case '"':
  2414.         tindex = ++sindex;
  2415.         temp = string_extract_double_quoted (string, &tindex);
  2416.         sindex = tindex;
  2417.  
  2418.         if (string[sindex])
  2419.           sindex++;
  2420.  
  2421.         temp1 = string_quote_removal (temp, 1);  /* XXX is this needed? */
  2422.  
  2423.         if (temp)
  2424.           free (temp);
  2425.  
  2426.         if (temp1)
  2427.           {
  2428.         strcpy (r, temp1);
  2429.         r += strlen (r);
  2430.         free (temp1);
  2431.           }
  2432.         break;
  2433.         
  2434.       case '\'':
  2435.         if (quoted)
  2436.           {
  2437.         *r++ = c;
  2438.         sindex++;
  2439.           }
  2440.         else
  2441.           {
  2442.         tindex = ++sindex;
  2443.         temp = string_extract_verbatim (string, &tindex, "'");
  2444.         sindex = tindex;
  2445.  
  2446.         if (string[sindex])
  2447.           sindex++;
  2448.  
  2449.         if (temp)
  2450.           {
  2451.             strcpy (r, temp);
  2452.             r += strlen (r);
  2453.             free (temp);
  2454.           }
  2455.           }
  2456.         break;
  2457.       default:
  2458.         *r++ = c;
  2459.         sindex++;
  2460.         break;
  2461.     }
  2462.     }
  2463.     *r = '\0';
  2464.     return (result_string);
  2465. }
  2466.  
  2467. /* Perform quote removal on word WORD.  This allocates and returns a new
  2468.    WORD_DESC *. */
  2469. WORD_DESC *
  2470. word_quote_removal (word, quoted)
  2471.      WORD_DESC *word;
  2472.      int quoted;
  2473. {
  2474.   WORD_DESC *w;
  2475.   char *t;
  2476.  
  2477.   t = string_quote_removal (word->word, quoted);
  2478.   w = make_word (t);
  2479.   return (w);
  2480. }
  2481.  
  2482. /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
  2483.    the members of the list are treated as if they are surrounded by
  2484.    double quotes.  Return a new list, or NULL if LIST is NULL. */
  2485. WORD_LIST *
  2486. word_list_quote_removal (list, quoted)
  2487.      WORD_LIST *list;
  2488.      int quoted;
  2489. {
  2490.   WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult;
  2491.  
  2492.   t = list;
  2493.   while (t)
  2494.     {
  2495.       tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
  2496.       tresult->word = word_quote_removal (t->word, quoted);
  2497.       tresult->next = (WORD_LIST *)NULL;
  2498.       result = (WORD_LIST *) list_append (result, tresult);
  2499.       t = t->next;
  2500.     }
  2501.   return (result);
  2502. }
  2503.  
  2504. #if defined (NOTDEF)
  2505. /* Currently unused. */
  2506. /* Return 1 if CHARACTER appears in an unquoted portion of
  2507.    STRING.  Return 0 otherwise. */
  2508. static int
  2509. unquoted_member (character, string)
  2510.      int character;
  2511.      char *string;
  2512. {
  2513.   int sindex, tindex, c;
  2514.   char *temp;
  2515.  
  2516.   sindex = 0;
  2517.  
  2518.   while (c = string[sindex])
  2519.     {
  2520.       if (c == character)
  2521.     return (1);
  2522.  
  2523.       switch (c)
  2524.     {
  2525.       case '\\':
  2526.         sindex++;
  2527.         if (string[sindex])
  2528.           sindex++;
  2529.         break;
  2530.       
  2531.       case '"':
  2532.       case '\'':
  2533.  
  2534.         tindex = ++sindex;
  2535.         if (c == '"')
  2536.           temp = string_extract_double_quoted (string, &tindex);
  2537.         else
  2538.           temp = string_extract_verbatim (string, &tindex, "'");
  2539.         sindex = tindex;
  2540.  
  2541.         if (string[sindex])
  2542.           sindex++;
  2543.  
  2544.         if (temp)
  2545.           free (temp);
  2546.         break;
  2547.         
  2548.       default:
  2549.         sindex++;
  2550.         break;
  2551.     }
  2552.     }
  2553.   return (0);
  2554. }
  2555. #endif /* NOTDEF */
  2556.  
  2557. /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
  2558. static int
  2559. unquoted_substring (substr, string)
  2560.      char *substr, *string;
  2561. {
  2562.   int sindex, tindex, c, sublen;
  2563.   char *temp;
  2564.  
  2565.   if (!substr || !*substr)
  2566.     return (0);
  2567.  
  2568.   sublen = strlen (substr);
  2569.   sindex = 0;
  2570.  
  2571.   while (c = string[sindex])
  2572.     {
  2573.       if (c == *substr &&
  2574.       strncmp (string + sindex, substr, sublen) == 0)
  2575.     return (1);
  2576.  
  2577.       switch (c)
  2578.     {
  2579.       case '\\':
  2580.         sindex++;
  2581.  
  2582.         if (string[sindex])
  2583.           sindex++;
  2584.         break;
  2585.       
  2586.       case '"':
  2587.       case '\'':
  2588.  
  2589.         tindex = ++sindex;
  2590.         if (c == '"')
  2591.           temp = string_extract_double_quoted (string, &tindex);
  2592.         else
  2593.           temp = string_extract_verbatim (string, &tindex, "'");
  2594.         sindex = tindex;
  2595.  
  2596.         if (string[sindex])
  2597.           sindex++;
  2598.  
  2599.         if (temp)
  2600.           free (temp);
  2601.  
  2602.         break;
  2603.         
  2604.       default:
  2605.         sindex++;
  2606.         break;
  2607.     }
  2608.     }
  2609.   return (0);
  2610. }
  2611.  
  2612. /*******************************************
  2613.  *                       *
  2614.  *    Functions to perform word splitting  *
  2615.  *                       *
  2616.  *******************************************/
  2617.  
  2618. /* This splits a single word into a WORD LIST on $IFS, but only if the word
  2619.    is not quoted.  list_string () performs quote removal for us, even if we
  2620.    don't do any splitting. */
  2621. WORD_LIST *
  2622. word_split (w)
  2623.      WORD_DESC *w;
  2624. {
  2625.   WORD_LIST *result;
  2626.  
  2627.   if (w)
  2628.     {
  2629.       SHELL_VAR *ifs = find_variable ("IFS");
  2630.       char *ifs_chars;
  2631.  
  2632.       /* If IFS is unset, it defaults to " \t\n". */
  2633.       if (ifs)
  2634.     ifs_chars = value_cell (ifs);
  2635.       else
  2636.     ifs_chars = " \t\n";
  2637.  
  2638.       if (w->quoted || !ifs_chars)
  2639.     ifs_chars = "";
  2640.  
  2641.       result = list_string (w->word, ifs_chars, w->quoted);
  2642.     }
  2643.   else
  2644.     result = (WORD_LIST *)NULL;
  2645.   return (result);
  2646. }
  2647.  
  2648. /* Perform word splitting on LIST and return the RESULT.  It is possible
  2649.    to return (WORD_LIST *)NULL. */
  2650. WORD_LIST *
  2651. word_list_split (list)
  2652.      WORD_LIST *list;
  2653. {
  2654.   WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult;
  2655.  
  2656.   t = list;
  2657.   while (t)
  2658.     {
  2659.       tresult = word_split (t->word);
  2660.       result = (WORD_LIST *) list_append (result, tresult);
  2661.       t = t->next;
  2662.     }
  2663.   return (result);
  2664. }
  2665.  
  2666. /**************************************************
  2667.  *                           *
  2668.  *    Functions to expand an entire WORD_LIST      *
  2669.  *                          *
  2670.  **************************************************/
  2671.  
  2672. /* Do all of the assignments in LIST up to a word which isn't an
  2673.    assignment. */
  2674. WORD_LIST *
  2675. get_rid_of_variable_assignments (list)
  2676.      WORD_LIST *list;
  2677. {
  2678.   WORD_LIST *orig = list;
  2679.  
  2680.   while (list)
  2681.     if (!list->word->assignment)
  2682.       {
  2683.     WORD_LIST *new_list = copy_word_list (list);
  2684.     dispose_words (orig);
  2685.     return (new_list);
  2686.       }
  2687.     else
  2688.       {
  2689.     do_assignment (list->word->word);
  2690.     list = list->next;
  2691.       }
  2692.   dispose_words (orig);
  2693.   return ((WORD_LIST *)NULL);
  2694. }
  2695.  
  2696. /* Check and handle the case where there are some variable assignments
  2697.    in LIST which go into the environment for this command. */
  2698. WORD_LIST *
  2699. get_rid_of_environment_assignments (list)
  2700.      WORD_LIST *list;
  2701. {
  2702.   register WORD_LIST *tlist = list;
  2703.   register WORD_LIST *new_list;
  2704.  
  2705.   while (tlist)
  2706.     {
  2707.       if (!tlist->word->assignment) goto make_assignments;
  2708.       tlist = tlist->next;
  2709.     }
  2710.   /* Since all of the assignments are variable assignments. */
  2711.   return (list);
  2712.  
  2713. make_assignments:
  2714.   tlist = list;
  2715.   while (tlist)
  2716.     {
  2717.       if (tlist->word->assignment)
  2718.     assign_in_env (tlist->word->word);
  2719.       else
  2720.     {
  2721.       if (!place_keywords_in_env)
  2722.         {
  2723.           new_list = copy_word_list (tlist);
  2724.           dispose_words (list);
  2725.           return (new_list);
  2726.         }
  2727.     }
  2728.       tlist = tlist->next;
  2729.     }
  2730.  
  2731.   /* We got all of the keywords assigned.  Now return the remainder
  2732.      of the words. */
  2733.   {
  2734.     register WORD_LIST *new_list = (WORD_LIST *)NULL;
  2735.  
  2736.     tlist = list;
  2737.  
  2738.     /* Skip the ones at the start. */
  2739.     while (tlist && tlist->word->assignment)
  2740.       tlist = tlist->next;
  2741.  
  2742.     /* If we placed all the keywords in the list into the environment,
  2743.        then remove them from the output list. */
  2744.     if (place_keywords_in_env)
  2745.       {
  2746.     while (tlist)
  2747.       {
  2748.         if (!tlist->word->assignment)
  2749.           new_list = make_word_list (copy_word (tlist->word), new_list);
  2750.         tlist = tlist->next;
  2751.       }
  2752.     new_list = (WORD_LIST *)reverse_list (new_list);
  2753.       }
  2754.     else
  2755.       {
  2756.     /* Just copy the list. */
  2757.     new_list = copy_word_list (tlist);
  2758.       }
  2759.     dispose_words (list);
  2760.     return (new_list);
  2761.   }
  2762. }
  2763.  
  2764. /* Take the list of words in LIST and do the various substitutions.  Return
  2765.    a new list of words which is the expanded list, and without things like
  2766.    variable assignments. */
  2767. static WORD_LIST *expand_words_internal ();
  2768.  
  2769. WORD_LIST *
  2770. expand_words (list)
  2771.      WORD_LIST *list;
  2772. {
  2773.   return (expand_words_internal (list, 1));
  2774. }
  2775.  
  2776. /* Same as expand_words (), but doesn't hack variable or environment
  2777.    variables. */
  2778. WORD_LIST *
  2779. expand_words_no_vars (list)
  2780.      WORD_LIST *list;
  2781. {
  2782.   return (expand_words_internal (list, 0));
  2783. }
  2784.  
  2785. /* Non-zero means to allow unmatched globbed filenames to expand to
  2786.    a null file. */
  2787. static int allow_null_glob_expansion = 0;
  2788.  
  2789. /* The workhorse for expand_words () and expand_words_no_var ().
  2790.    First arg is LIST, a WORD_LIST of words.
  2791.    Second arg DO_VARS is non-zero if you want to do environment and
  2792.    variable assignments, else zero.
  2793.  
  2794.    This does all of the subsitutions: brace expansion, tilde expansion,
  2795.    parameter expansion, command substitution, arithmetic expansion,
  2796.    word splitting, and pathname expansion. */
  2797. static WORD_LIST *
  2798. expand_words_internal (list, do_vars)
  2799.      WORD_LIST *list;
  2800.      int do_vars;
  2801. {
  2802.   register WORD_LIST *tlist, *new_list = (WORD_LIST *)NULL;
  2803.   WORD_LIST *orig_list;
  2804.   extern int no_brace_expansion;
  2805.  
  2806.   tlist = (WORD_LIST *)copy_word_list (list);
  2807.  
  2808.   if (do_vars)
  2809.     {
  2810.       /* Handle the case where the arguments are assignments for
  2811.      the environment of this command. */
  2812.       tlist = get_rid_of_environment_assignments (tlist);
  2813.  
  2814.       /* Handle the case where the arguments are all variable assignments. */
  2815.       tlist = get_rid_of_variable_assignments (tlist);
  2816.     }
  2817.  
  2818.   /* Begin expanding the words that remain.  The expansions take place on
  2819.      things that aren't really variable assignments. */
  2820.  
  2821.   if (!tlist)
  2822.     return ((WORD_LIST *)NULL);
  2823.  
  2824.   /* Do brace expansion on this word if there are any brace characters
  2825.      in the string. */
  2826.   if (!no_brace_expansion)
  2827.     {
  2828.       extern char **brace_expand ();
  2829.       register char **expansions;
  2830.       WORD_LIST *braces = (WORD_LIST *)NULL;
  2831.       int eindex;
  2832.  
  2833.       orig_list = tlist;
  2834.  
  2835.       while (tlist)
  2836.     {
  2837.       /* Only do brace expansion if the word has a brace character.  If
  2838.          not, just copy the word list element, add it to braces, and
  2839.          continue.  In the common case, at least when running shell
  2840.          scripts, this will degenerate to a bunch of calls to `index',
  2841.          and then what is basically the body of copy_word_list. */
  2842.       if (index (tlist->word->word, '{') != NULL)
  2843.         {
  2844.           expansions = brace_expand (tlist->word->word);
  2845.  
  2846.           for (eindex = 0; expansions[eindex]; eindex++)
  2847.         {
  2848.           braces = make_word_list (make_word (expansions[eindex]),
  2849.                          braces);
  2850.           free (expansions[eindex]);
  2851.         }
  2852.           free (expansions);
  2853.         }
  2854.       else
  2855.         {
  2856.           WORD_LIST *new = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
  2857.           new->word = copy_word (tlist->word);
  2858.           new->next = braces;
  2859.           braces = new;
  2860.         }
  2861.  
  2862.       tlist = tlist->next;
  2863.     }
  2864.       dispose_words (orig_list);
  2865.       tlist = (WORD_LIST *)reverse_list (braces);
  2866.     }
  2867.  
  2868.   orig_list = tlist;
  2869.  
  2870.   /* We do tilde expansion all the time.  This is what 1003.2 says. */
  2871.   while (tlist)
  2872.     {
  2873.       register char *current_word;
  2874.       WORD_LIST *expanded, *t;
  2875.       int expanded_something = 0;
  2876.  
  2877.       current_word = tlist->word->word;
  2878.  
  2879.       if (current_word[0] == '~' ||
  2880.       (index (current_word, '~') &&
  2881.        unquoted_substring ("=~", current_word)))
  2882.     {
  2883.       char *tilde_expand (), *tt;
  2884.  
  2885.       tt = tlist->word->word;
  2886.       tlist->word->word = tilde_expand (tt);
  2887.       free (tt);
  2888.     }
  2889.  
  2890.       expanded = expand_word_internal
  2891.     (tlist->word, 0, (int *)NULL, &expanded_something);
  2892.  
  2893.       if (expanded_something)
  2894.     t = word_list_split (expanded);
  2895.       else
  2896.     {
  2897.       /* If no parameter expansion, command substitution, or arithmetic
  2898.          substitution took place, then do not do word splitting.  We
  2899.          still have to remove quoted null characters from the result. */
  2900.       word_list_remove_quoted_nulls (expanded);
  2901.       t = copy_word_list (expanded);
  2902.     }
  2903.  
  2904.       new_list =
  2905.     (WORD_LIST *)list_append (reverse_list (t), new_list);
  2906.  
  2907.       dispose_words (expanded);
  2908.  
  2909.       tlist = tlist->next;
  2910.     }
  2911.  
  2912.   new_list = (WORD_LIST *)reverse_list (new_list);
  2913.  
  2914.   dispose_words (orig_list);
  2915.  
  2916.   /* Okay, we're almost done.  Now let's just do some filename
  2917.      globbing. */
  2918.   {
  2919.     char **shell_glob_filename (), **temp_list = (char **)NULL;
  2920.     register int list_index;
  2921.     WORD_LIST *glob_list;
  2922.  
  2923.     orig_list = (WORD_LIST *)NULL;
  2924.     tlist = new_list;
  2925.  
  2926.     if (!disallow_filename_globbing)
  2927.       {
  2928.     while (tlist)
  2929.       {
  2930.         /* If the word isn't quoted, then glob it. */
  2931.         if (!tlist->word->quoted && glob_pattern_p (tlist->word->word, 0))
  2932.           {
  2933.         temp_list = shell_glob_filename (tlist->word->word);
  2934.  
  2935.         /* Fix the hi-bits. (This is how we quoted
  2936.            special characters.) */
  2937.         {
  2938.           register char *t = dequote_string (tlist->word->word);
  2939.           free (tlist->word->word);
  2940.           tlist->word->word = t;
  2941.         }
  2942.  
  2943.         /* Handle error cases.
  2944.            I don't think we should report errors like "No such file
  2945.            or directory".  However, I would like to report errors
  2946.            like "Read failed". */
  2947.  
  2948. #if defined (USE_GLOB_LIBRARY)
  2949.         if (!temp_list)
  2950. #else
  2951.         if (temp_list == (char **)-1)
  2952. #endif /* !USE_GLOB_LIBRARY */
  2953.           {
  2954.             /* file_error (tlist->word->word); */
  2955.             /* A small memory leak, I think */
  2956.             temp_list = (char **) xmalloc (sizeof (char *));
  2957.             temp_list[0] = '\0';
  2958.           }
  2959.  
  2960. #if !defined (USE_GLOB_LIBRARY)
  2961.         if (!temp_list)
  2962.           abort ();
  2963. #endif /* !USE_GLOB_LIBRARY */
  2964.  
  2965.         /* Make the array into a word list. */
  2966.         glob_list = (WORD_LIST *)NULL;
  2967.         for (list_index = 0; temp_list[list_index]; list_index++)
  2968.           glob_list =
  2969.             make_word_list (make_word (temp_list[list_index]), glob_list);
  2970.  
  2971.         if (glob_list)
  2972.           orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
  2973.         else
  2974.           if (!allow_null_glob_expansion)
  2975.             orig_list =
  2976.               make_word_list (copy_word (tlist->word), orig_list);
  2977.           }
  2978.         else
  2979.           {
  2980.         /* Fix the hi-bits. (This is how we quoted special
  2981.            characters.) */
  2982.         register char *t = dequote_string (tlist->word->word);
  2983.         free (tlist->word->word);
  2984.         tlist->word->word = t;
  2985.         orig_list = make_word_list (copy_word (tlist->word), orig_list);
  2986.           }
  2987.  
  2988.         free_array (temp_list);
  2989.         temp_list = (char **)NULL;
  2990.  
  2991.         tlist = tlist->next;
  2992.       }
  2993.     dispose_words (new_list);
  2994.     new_list = orig_list;
  2995.       }
  2996.     else
  2997.       {
  2998.     /* Fix the hi-bits. (This is how we quoted special characters.) */
  2999.     register WORD_LIST *wl = new_list;
  3000.     register char *wp;
  3001.     while (wl)
  3002.       {
  3003.         wp = dequote_string (wl->word->word);
  3004.         free (wl->word->word);
  3005.         wl->word->word = wp;
  3006.         wl = wl->next;
  3007.       }
  3008.     return (new_list);
  3009.       }
  3010.   }
  3011.   return (WORD_LIST *)(reverse_list (new_list));
  3012. }
  3013.  
  3014. /* Call the glob library to do globbing on PATHNAME.
  3015.    PATHNAME can contain characters with the hi bit set; this indicates
  3016.    that the character is to be quoted.  We quote it here. */
  3017. char **
  3018. shell_glob_filename (pathname)
  3019.      char *pathname;
  3020. #if defined (USE_GLOB_LIBRARY)
  3021. {
  3022.   extern int glob_dot_filenames;
  3023.   register int i, j;
  3024.   char *temp, **return_value;
  3025.   glob_t filenames;
  3026.   int glob_flags;
  3027.  
  3028.   temp = (char *)alloca (1 + (2 * strlen (pathname)));
  3029.  
  3030.   for (i = j = 0; pathname[i]; i++, j++)
  3031.     {
  3032.       if (QUOTED_CHAR (pathname[i]))
  3033.     temp[j++] = '\\';
  3034.  
  3035.       temp[j] = DEQUOTE_CHAR (pathname[i]);
  3036.     }
  3037.   temp[j] = '\0';
  3038.  
  3039.   filenames.gl_offs = 0;
  3040.  
  3041.   glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
  3042.   glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
  3043.  
  3044.   i = glob (temp, glob_flags, (Function *)NULL, &filenames);
  3045.  
  3046.   if (i == GLOB_NOSPACE || i == GLOB_ABEND)
  3047.     return ((char **)NULL);
  3048.  
  3049.   if (i == GLOB_NOMATCH)
  3050.     filenames.gl_pathv[0] = (char *)NULL;
  3051.  
  3052.   return (filenames.gl_pathv);
  3053. }
  3054. #else /* !USE_GLOB_LIBRARY */
  3055. {
  3056.   extern char **glob_filename ();
  3057.   extern int glob_dot_filenames, noglob_dot_filenames;
  3058.   register int i, j;
  3059.   char *temp, **results;
  3060.  
  3061.   temp = (char *)alloca (1 + (2 * strlen (pathname)));
  3062.  
  3063.   noglob_dot_filenames = !glob_dot_filenames;
  3064.  
  3065.   for (i = j = 0; pathname[i]; i++, j++)
  3066.     {
  3067.       if (QUOTED_CHAR (pathname[i]))
  3068.     {
  3069.       temp[j++] = '\\';
  3070.       temp[j] = DEQUOTE_CHAR (pathname[i]);
  3071.     }
  3072.       else
  3073.     temp[j] = pathname[i];
  3074.     }
  3075.   temp[j] = '\0';
  3076.  
  3077.   results = glob_filename (temp);
  3078.  
  3079.   if (results && results != (char **)-1)
  3080.     sort_char_array (results);
  3081.  
  3082.   return (results);
  3083. }
  3084. #endif /* !USE_GLOB_LIBRARY */
  3085.  
  3086. /*************************************************
  3087.  *                         *
  3088.  *    Functions to manage special variables     *
  3089.  *                         *
  3090.  *************************************************/
  3091.  
  3092. /* An alist of name.function for each special variable.  Most of the
  3093.    functions don't do much, and in fact, this would be faster with a
  3094.    switch statement, but by the end of this file, I am sick of switch
  3095.    statements. */
  3096.  
  3097. /* The functions that get called. */
  3098. int
  3099.   sv_path (), sv_mail (), sv_terminal (), sv_histsize (), sv_histfilesize (),
  3100.   sv_uids (), sv_ignoreeof (), sv_glob_dot_filenames (), sv_histchars (),
  3101.   sv_nolinks (), sv_hostname_completion_file (), sv_history_control (),
  3102.   sv_noclobber (), sv_allow_null_glob_expansion (),
  3103.   sv_command_oriented_history ();
  3104.  
  3105. #if defined (GETOPTS_BUILTIN)
  3106. int sv_optind (), sv_opterr ();
  3107. #endif /* GETOPTS_BUILTIN */
  3108.  
  3109. #if defined (JOB_CONTROL)
  3110. extern int sv_notify ();
  3111. #endif
  3112.  
  3113. struct name_and_function {
  3114.   char *name;
  3115.   Function *function;
  3116. } special_vars[] = {
  3117.   { "PATH", sv_path },
  3118.   { "MAIL", sv_mail },
  3119.   { "MAILPATH", sv_mail },
  3120.   { "MAILCHECK", sv_mail },
  3121.   { "TERMCAP", sv_terminal },
  3122.   { "TERM", sv_terminal },
  3123.   { "HISTSIZE", sv_histsize },
  3124.   { "HISTFILESIZE", sv_histfilesize },
  3125.   { "EUID", sv_uids},
  3126.   { "UID", sv_uids},
  3127.   { "IGNOREEOF", sv_ignoreeof },
  3128.   { "ignoreeof", sv_ignoreeof },
  3129. #if defined (GETOPTS_BUILTIN)
  3130.   { "OPTIND", sv_optind },
  3131.   { "OPTERR", sv_opterr },
  3132. #endif /* GETOPTS_BUILTIN */
  3133. #if defined (JOB_CONTROL)
  3134.   { "notify", sv_notify },
  3135. #endif  /* JOB_CONTROL */
  3136.   { "glob_dot_filenames", sv_glob_dot_filenames },
  3137.   { "allow_null_glob_expansion", sv_allow_null_glob_expansion },
  3138.   { "command_oriented_history", sv_command_oriented_history },
  3139.   { "histchars", sv_histchars },
  3140.   { "hostname_completion_file", sv_hostname_completion_file },
  3141.   { "history_control", sv_history_control },
  3142.   { "noclobber", sv_noclobber },
  3143.   { "nolinks", sv_nolinks },
  3144.   { (char *)0x00, (Function *)0x00 }
  3145. };
  3146.  
  3147. /* The variable in NAME has just had its state changed.  Check to see if it
  3148.    is one of the special ones where something special happens. */
  3149. stupidly_hack_special_variables (name)
  3150.      char *name;
  3151. {
  3152.   int i = 0;
  3153.  
  3154.   while (special_vars[i].name)
  3155.     {
  3156.       if (STREQ (special_vars[i].name, name))
  3157.     {
  3158.       (*(special_vars[i].function)) (name);
  3159.       return;
  3160.     }
  3161.       i++;
  3162.     }
  3163. }
  3164.  
  3165. /* Set/unset noclobber. */
  3166. sv_noclobber (name)
  3167.      char *name;
  3168. {
  3169.   extern int noclobber;
  3170.  
  3171.   if (find_variable (name))
  3172.     noclobber = 1;
  3173.   else
  3174.     noclobber = 0;
  3175. }
  3176.  
  3177. /* What to do just after the PATH variable has changed. */
  3178. sv_path (name)
  3179.      char *name;
  3180. {
  3181.   /* hash -r */
  3182.   WORD_LIST *args;
  3183.  
  3184.   args = make_word_list (make_word ("-r"), NULL);
  3185.   hash_builtin (args);
  3186.   dispose_words (args);
  3187. }
  3188.  
  3189. /* What to do just after one of the MAILxxxx variables has changed.  NAME
  3190.    is the name of the variable.  */
  3191. sv_mail (name)
  3192.      char *name;
  3193. {
  3194.   /* If the time interval for checking the files has changed, then
  3195.      reset the mail timer.  Otherwise, one of the pathname vars
  3196.      to the users mailbox has changed, so rebuild the array of
  3197.      filenames. */
  3198.   if (strcmp (name, "MAILCHECK") == 0)
  3199.     reset_mail_timer ();
  3200.   else
  3201.     {
  3202.       if ((strcmp (name, "MAIL") == 0) || (strcmp (name, "MAILPATH") == 0))
  3203.     {
  3204.       free_mail_files ();
  3205.       remember_mail_dates ();
  3206.     }
  3207.     }
  3208. }
  3209.  
  3210. /* What to do just after one of the TERMxxx variables has changed.
  3211.    If we are an interactive shell, then try to reset the terminal
  3212.    information in readline. */
  3213. sv_terminal (name)
  3214.      char *name;
  3215. {
  3216.   extern int interactive;
  3217.  
  3218.   if (interactive)
  3219.     rl_reset_terminal (get_string_value ("TERM"));
  3220. }
  3221.  
  3222. /* What to do after the HISTSIZE variable changes.
  3223.    If there is a value for this variable (and it is numeric), then stifle
  3224.    the history.  Otherwise, if there is NO value for this variable,
  3225.    unstifle the history. */
  3226. sv_histsize (name)
  3227.      char *name;
  3228. {
  3229.   char *temp = get_string_value (name);
  3230.  
  3231.   if (temp)
  3232.     {
  3233.       int num;
  3234.       if (sscanf (temp, "%d", &num) == 1)
  3235.     {
  3236.       extern int history_lines_this_session;
  3237.  
  3238.       stifle_history (num);
  3239.       if (history_lines_this_session > where_history ())
  3240.         history_lines_this_session = where_history ();
  3241.     }
  3242.     }
  3243.   else
  3244.     unstifle_history ();
  3245. }
  3246.  
  3247. /* What to do if the HISTFILESIZE variable changes. */
  3248. sv_histfilesize (name)
  3249.      char *name;
  3250. {
  3251.   char *temp = get_string_value (name);
  3252.  
  3253.   if (temp)
  3254.     {
  3255.       extern int history_lines_in_file;
  3256.       int num;
  3257.       if (sscanf (temp, "%d", &num) == 1)
  3258.     {
  3259.       history_truncate_file (get_string_value ("HISTFILE"), num);
  3260.       if (num <= history_lines_in_file)
  3261.         history_lines_in_file = num;
  3262.     }
  3263.     }
  3264. }
  3265.  
  3266. /* A nit for picking at history saving.
  3267.    Value of 0 means save all lines parsed by the shell on the history.
  3268.    Value of 1 means save all lines that do not start with a space.
  3269.    Value of 2 means save all lines that do not match the last line saved. */
  3270. int history_control = 0;
  3271.  
  3272. /* What to do after the HISTORY_CONTROL variable changes. */
  3273. sv_history_control (name)
  3274.      char *name;
  3275. {
  3276.   char *temp = get_string_value (name);
  3277.  
  3278.   history_control = 0;
  3279.  
  3280.   if (temp && *temp)
  3281.     {
  3282.       if (strcmp (temp, "ignorespace") == 0)
  3283.     history_control = 1;
  3284.       else if (strcmp (temp, "ignoredups") == 0)
  3285.     history_control = 2;
  3286.     }
  3287. }
  3288.  
  3289. /* By default, every line is saved in the history individually.  I.e.,
  3290.    if the user enters:
  3291.     bash$ for i in a b c
  3292.         > do
  3293.         > echo $i
  3294.         > done
  3295.    Each line will be individually saved in the history. 
  3296.     bash$ history
  3297.     10  for i in a b c
  3298.         11  do
  3299.         12  echo $i
  3300.         13  done
  3301.         14  history
  3302.    If the variable command_oriented_history is set, multiple lines
  3303.    which form one command will be saved as one history entry.
  3304.     bash$ for i in a b c
  3305.         > do
  3306.         > echo $i
  3307.         > done
  3308.         bash$ history
  3309.     10  for i in a b c
  3310.     do
  3311.     echo $i
  3312.     done
  3313.         11  history
  3314.    The user can then recall the whole command all at once instead
  3315.    of just being able to recall one line at a time.
  3316.    */
  3317. int command_oriented_history = 0;
  3318.  
  3319. /* What to do after the COMMAND_ORIENTED_HISTORY variable changes. */
  3320. sv_command_oriented_history (name)
  3321.      char *name;
  3322. {
  3323.   if (find_variable (name) != (SHELL_VAR *)NULL)
  3324.     command_oriented_history = 1;
  3325.   else
  3326.     command_oriented_history = 0;
  3327. }
  3328.  
  3329. /* If the variable exists, then the value of it can be the number
  3330.    of times we actually ignore the EOF.  The default is small,
  3331.    (smaller than csh, anyway). */
  3332. sv_ignoreeof (name)
  3333.      char *name;
  3334. {
  3335.   extern int eof_encountered, eof_encountered_limit;
  3336.   char *temp = get_string_value (name);
  3337.   int new_limit;
  3338.  
  3339.   eof_encountered = 0;
  3340.  
  3341.   if (temp && (sscanf (temp, "%d", &new_limit) == 1))
  3342.     eof_encountered_limit = new_limit;
  3343.   else
  3344.     eof_encountered_limit = 10; /* csh uses 26. */
  3345. }
  3346.  
  3347. /* Control whether * matches .files in globbing.  Yechh. */
  3348. int glob_dot_filenames = 0;
  3349.  
  3350. sv_glob_dot_filenames (name)
  3351.      char *name;
  3352. {
  3353.   if (find_variable (name) != (SHELL_VAR *)NULL)
  3354.     glob_dot_filenames = 1;
  3355.   else
  3356.     glob_dot_filenames = 0;
  3357. }
  3358.  
  3359. /* Setting/unsetting of the history expansion character. */
  3360. char old_history_expansion_char = '!';
  3361. char old_history_comment_char = '#';
  3362. char old_history_subst_char = '^';
  3363.  
  3364. sv_histchars (name)
  3365.      char *name;
  3366. {
  3367.   extern char history_expansion_char;
  3368.   extern char history_comment_char;
  3369.   extern char history_subst_char;
  3370.   char *temp = get_string_value (name);
  3371.  
  3372.   if (temp)
  3373.     {
  3374.       old_history_expansion_char = history_expansion_char;
  3375.       history_expansion_char = *temp;
  3376.  
  3377.       if (temp[1])
  3378.     {
  3379.       old_history_subst_char = history_subst_char;
  3380.       history_subst_char = temp[1];
  3381.  
  3382.       if (temp[2])
  3383.         {
  3384.           old_history_comment_char = history_comment_char;
  3385.           history_comment_char = temp[2];
  3386.         }
  3387.     }
  3388.     }
  3389.   else
  3390.     {
  3391.       history_expansion_char = '!';
  3392.       history_subst_char = '^';
  3393.       history_comment_char = '#';
  3394.     }
  3395. }
  3396.  
  3397. #if defined (JOB_CONTROL)
  3398. /* Job notification feature desired? */
  3399. sv_notify (name)
  3400.      char *name;
  3401. {
  3402.   extern int asynchronous_notification;
  3403.  
  3404.   if (get_string_value (name))
  3405.     asynchronous_notification = 1;
  3406.   else
  3407.     asynchronous_notification = 0;
  3408. }
  3409. #endif  /* JOB_CONTROL */
  3410.  
  3411. /* If the variable `nolinks' exists, it specifies that symbolic links are
  3412.    not to be followed in `cd' commands. */
  3413. sv_nolinks (name)
  3414.      char *name;
  3415. {
  3416.   extern int follow_symbolic_links;
  3417.  
  3418.   follow_symbolic_links = !find_variable (name);
  3419. }
  3420.  
  3421. /* Don't let users hack the user id variables. */
  3422. sv_uids (name)
  3423.      char *name;
  3424. {
  3425.   int uid = getuid ();
  3426.   int euid = geteuid ();
  3427.   char buff[10];
  3428.   register SHELL_VAR *v;
  3429.  
  3430.   sprintf (buff, "%d", uid);
  3431.   v = find_variable ("UID");
  3432.   if (v)
  3433.     v->attributes &= ~att_readonly;
  3434.  
  3435.   v = bind_variable ("UID", buff);
  3436.   v->attributes |= (att_readonly | att_integer);
  3437.  
  3438.   sprintf (buff, "%d", euid);
  3439.   v = find_variable ("EUID");
  3440.   if (v)
  3441.     v->attributes &= ~att_readonly;
  3442.  
  3443.   v = bind_variable ("EUID", buff);
  3444.   v->attributes |= (att_readonly | att_integer);
  3445. }
  3446.  
  3447. sv_hostname_completion_file (name)
  3448.      char *name;
  3449. {
  3450.   extern int hostname_list_initialized;
  3451.  
  3452.   hostname_list_initialized = 0;
  3453. }
  3454.  
  3455. sv_allow_null_glob_expansion (name)
  3456.      char *name;
  3457. {
  3458.   allow_null_glob_expansion = (int)find_variable (name);
  3459. }
  3460.  
  3461. #if defined (GETOPTS_BUILTIN)
  3462. sv_optind (name)
  3463.      char *name;
  3464. {
  3465.   char *tt = get_string_value ("OPTIND");
  3466.   int s = 0;
  3467.  
  3468.   if (tt && *tt)
  3469.     {
  3470.       s = atoi (tt);
  3471.  
  3472.       /* According to POSIX, setting OPTIND=1 resets the internal state
  3473.      of getopt (). */
  3474.       if (s < 0 || s == 1)
  3475.     s = 0;
  3476.     }
  3477.   getopts_reset (s);
  3478. }
  3479.  
  3480. int
  3481. sv_opterr (name)
  3482.      char *name;
  3483. {
  3484.   char *tt = get_string_value ("OPTERR");
  3485.   int s = 1;
  3486.   extern int opterr;
  3487.  
  3488.   if (tt)
  3489.     s = atoi (tt);
  3490.   opterr = s;
  3491.   return (0);
  3492. }
  3493. #endif /* GETOPTS_BUILTIN */
  3494.