home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / BASH_112.ZIP / BASH-112.TAR / bash-1.12 / variables.c < prev    next >
C/C++ Source or Header  |  1993-02-14  |  41KB  |  1,613 lines

  1. /* variables.c -- Functions for hacking shell variables. */
  2.  
  3. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  4.  
  5.    This file is part of GNU Bash, the Bourne Again SHell.
  6.  
  7.    Bash is free software; you can redistribute it and/or modify it
  8.    under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 1, or (at your option)
  10.    any later version.
  11.  
  12.    Bash is distributed in the hope that it will be useful, but WITHOUT
  13.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14.    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  15.    License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with Bash; see the file COPYING.  If not, write to the Free
  19.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <pwd.h>
  24. #include <sys/types.h>
  25.  
  26. #include "shell.h"
  27. #include "hash.h"
  28. #include "flags.h"
  29.  
  30. #if defined (USG) && !defined (isc386) && !defined (sgi)
  31. struct passwd *getpwuid (), *getpwent ();
  32. #endif
  33.  
  34. /* The list of shell variables that the user has created, or that came from
  35.    the environment. */
  36. HASH_TABLE *shell_variables = (HASH_TABLE *)NULL;
  37.  
  38. /* The list of shell functions that the user has created, or that came from
  39.    the environment. */
  40. HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
  41.  
  42. /* The current variable context.  This is really a count of how deep into
  43.    executing functions we are. */
  44. int variable_context = 0;
  45.  
  46. /* The array of shell assignments which are made only in the environment
  47.    for a single command. */
  48. char **temporary_env = (char **)NULL;
  49.  
  50. /* Some funky variables which are known about specially.  Here is where
  51.    "$*", "$1", and all the cruft is kept. */
  52. char *dollar_vars[10];
  53. WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
  54.  
  55. /* The value of $$. */
  56. int dollar_dollar_pid;
  57.  
  58. /* An array which is passed to commands as their environment.  It is
  59.    manufactured from the overlap of the initial environment and the
  60.    shell variables that are marked for export. */
  61. char **export_env = (char **)NULL;
  62.  
  63. /* Non-zero means that we have to remake EXPORT_ENV. */
  64. int array_needs_making = 1;
  65.  
  66. /* The list of variables that may not be unset in this shell. */
  67. char **non_unsettable_vars = (char **)NULL;
  68.  
  69. #if defined (USG)
  70. #define DEFAULT_MAIL_PATH "/usr/mail/"
  71. #else
  72. #define DEFAULT_MAIL_PATH "/usr/spool/mail/"
  73. #endif
  74.  
  75. #if !defined(HOSTTYPE)
  76. #define HOSTTYPE "i386"
  77. #endif
  78.  
  79. /* Some forward declarations. */
  80. SHELL_VAR *set_if_not ();    /* returns new or existing entry */
  81. static void sbrand ();        /* set bash random number generator */
  82.  
  83. /* Make VAR be auto-exported.  VAR is a pointer to a SHELL_VAR. */
  84. #define set_auto_export(var) \
  85. { var->attributes |= att_exported; array_needs_making = 1; }
  86.  
  87. /* Initialize the shell variables from the current environment. */
  88. initialize_shell_variables (env)
  89.      char *env[];
  90. {
  91.   extern char *primary_prompt, *secondary_prompt;
  92.   char *name, *string;
  93.   int c, char_index;
  94.   int string_index = 0;
  95.   SHELL_VAR *temp_var;
  96.  
  97.   if (!shell_variables)
  98.     shell_variables = make_hash_table (0);
  99.  
  100.   if (!shell_functions)
  101.     shell_functions = make_hash_table (0);
  102.  
  103.   /* Set up $PWD. */
  104.   {
  105.     char *get_working_directory (), *cd;
  106.  
  107.     cd = get_working_directory ("shell-init");
  108.     if (cd)
  109.       {
  110.     bind_variable ("PWD", cd);
  111.     free (cd);
  112.       }
  113.   }
  114.  
  115.   while (string = env[string_index++])
  116.     {
  117.       char_index = 0;
  118.  
  119.       name = (char *)alloca (1 + strlen (string));
  120.  
  121.       while ((c = *string++) && c != '=')
  122.     name[char_index++] = c;
  123.  
  124.       name[char_index] = '\0';
  125.  
  126.       /* If exported function, define it now. */
  127.       /* Posix.2 style exported function: name()=value */
  128.       if (strncmp ("() {", string, 4) == 0 ||
  129.       ((name[char_index - 1] == ')' &&
  130.         name[char_index - 2] == '(' &&
  131.         string[0] == '{')))
  132.     {
  133.       char *eval_string;
  134.  
  135.       eval_string = (char *)xmalloc (3 + strlen (string) + strlen (name));
  136.       sprintf (eval_string, "%s %s", name, string);
  137.       parse_and_execute (eval_string, name);
  138.  
  139.       if (name[char_index - 1] == ')')
  140.         name[char_index - 2] = '\0';
  141.       set_func_auto_export (name);
  142.     }
  143.       else
  144.     {
  145.       SHELL_VAR *v;
  146.  
  147.       v = bind_variable (name, string);
  148.       set_auto_export (v);
  149.     }
  150.     }
  151.  
  152.   /* Remember this pid. */
  153.   dollar_dollar_pid = (int)getpid ();
  154.  
  155.   /* Now make our own defaults in case the vars that we think are
  156.      important are missing. */
  157.   temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
  158.   set_auto_export (temp_var);
  159.  
  160.   temp_var = set_if_not ("TERM", "dumb");
  161.   set_auto_export (temp_var);
  162.  
  163.   set_if_not ("PS1", primary_prompt);
  164.   set_if_not ("PS2", secondary_prompt);
  165.   set_if_not ("IFS", " \t\n");
  166.  
  167.   /* Magic machine types.  Pretty convenient. */
  168.   temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
  169.   set_auto_export (temp_var);
  170.  
  171.   /* Default MAILPATH, and MAILCHECK. */
  172.   set_if_not ("MAILCHECK", "60");
  173.   if ((get_string_value ("MAIL") == (char *)NULL) &&
  174.       (get_string_value ("MAILPATH") == (char *)NULL))
  175.     {
  176.       extern char *current_user_name;
  177.       char *tem;
  178.  
  179.       tem = (char *)xmalloc (1 + sizeof (DEFAULT_MAIL_PATH)
  180.                + strlen (current_user_name));
  181.       strcpy (tem, DEFAULT_MAIL_PATH);
  182.       strcat (tem, current_user_name);
  183.  
  184.       bind_variable ("MAILPATH", tem);
  185.       free (tem);
  186.     }
  187.  
  188.   /* Do some things with shell level. */
  189.   temp_var = set_if_not ("SHLVL", "0");
  190.   set_auto_export (temp_var);
  191.   adjust_shell_level (1);
  192.  
  193.   /* Make a variable $PPID, which holds the pid of the shell's parent.  */
  194.   {
  195.     char *ppid;
  196.     SHELL_VAR *v;
  197.     extern char *itos ();
  198.  
  199.     ppid = itos ((int) getppid ());
  200.     v = find_variable ("PPID");
  201.  
  202.     if (v)
  203.       v->attributes &= ~att_readonly;
  204.  
  205.     v = bind_variable ("PPID", ppid);
  206.     v->attributes |= (att_readonly | att_integer);
  207.  
  208.     non_unsettable ("PPID");
  209.     free (ppid);
  210.   }
  211.  
  212. #if defined (GETOPTS_BUILTIN)
  213.   /* Initialize the `getopts' stuff. */
  214.   bind_variable ("OPTIND", "1");
  215.   bind_variable ("OPTERR", "1");
  216. #endif /* GETOPTS_BUILTIN */
  217.  
  218.   /* Get the full pathname to THIS shell, and set the BASH variable
  219.      to it. */
  220.   {
  221.     extern char *shell_name, *find_user_command (), *full_pathname ();
  222.     extern int login_shell;
  223.     char *tname = find_user_command (shell_name);
  224.  
  225.     if ((login_shell == 1) && (*shell_name != '/'))
  226.       {
  227.     struct passwd *entry = getpwuid (getuid ());
  228.  
  229.     if (entry)
  230.       {
  231.         /* If HOME doesn't exist, set it. */
  232.         temp_var = (SHELL_VAR *)find_variable ("HOME");
  233.         if (!temp_var)
  234.           {
  235.         temp_var = bind_variable ("HOME", entry->pw_dir);
  236.         temp_var->attributes |= att_exported;
  237.           }
  238.         name = savestring (entry->pw_shell);
  239.       }
  240.     else
  241.       name = savestring ("a.out");
  242.     endpwent ();
  243.       }
  244.     else
  245.       {
  246.     if (!tname)
  247.       {
  248.         char *make_absolute ();
  249.         name = make_absolute (shell_name, get_string_value ("PWD"));
  250.       }
  251.     else
  252.       {
  253.         name = full_pathname (tname);
  254.         free (tname);
  255.       }
  256.       }
  257.  
  258.     /* Make the exported environment variable SHELL be whatever the name of
  259.        this shell is.  Note that the `tset' command looks at this variable
  260.        to determine what style of commands to output; if it ends in "csh",
  261.        then C-shell commands are output, else Bourne shell commands. */
  262.     temp_var = set_if_not ("SHELL", name);
  263.     set_auto_export (temp_var);
  264.  
  265.     /* Make a variable called BASH, which is the name of THIS shell. */
  266.     temp_var = bind_variable ("BASH", name);
  267.     temp_var->attributes |= att_exported;
  268.  
  269.     free (name);
  270.   }
  271.  
  272.   /* Make a variable called BASH_VERSION which contains the version info. */
  273.   {
  274.     char tt[12];
  275.     extern char *dist_version;
  276.     extern int build_version;
  277.  
  278.     sprintf (tt, "%s.%d", dist_version, build_version);
  279.     bind_variable ("BASH_VERSION", tt);
  280.   }
  281.  
  282.   /* Set history variables to defaults, and then do whatever we would
  283.      do if the variable had just been set. */
  284.   {
  285.     char *tilde_expand ();
  286.     char *tem = tilde_expand ("~/.bash_history");
  287.  
  288.     set_if_not ("HISTFILE", tem);
  289.     free (tem);
  290.  
  291.     set_if_not ("HISTSIZE", "500");
  292.     sv_histsize ("HISTSIZE");
  293.   }
  294.  
  295.   /* seed the random number generator */
  296.  
  297.   sbrand (dollar_dollar_pid);
  298.  
  299.   /* If we have inherited `noclobber' from a previous shell, then set
  300.      noclobbering on. */
  301.   {
  302.     extern int noclobber;
  303.  
  304.     noclobber = find_variable ("noclobber") != NULL;
  305.   }
  306.  
  307.   /* Initialize the dynamic variables, and seed their values */
  308.   initialize_dynamic_variables ();
  309.  
  310.   non_unsettable ("PATH");
  311.   non_unsettable ("PS1");
  312.   non_unsettable ("PS2");
  313.   non_unsettable ("IFS");
  314.  
  315.   /* Get the users real user id, and save that in an readonly variable.
  316.      To make the variable *really* readonly, we have added it to a special
  317.      list of vars. */
  318.  
  319.   sv_uids ();
  320.   set_var_read_only ("UID");
  321.   set_var_read_only ("EUID");
  322.  
  323.   non_unsettable ("EUID");
  324.   non_unsettable ("UID");
  325. }
  326.  
  327. adjust_shell_level (change)
  328.      int change;
  329. {
  330.   extern int shell_level;
  331.   extern char *itos ();
  332.   char *new_level;
  333.   int old_level;
  334.  
  335.  
  336.   old_level = atoi (get_string_value ("SHLVL"));
  337.   shell_level = old_level + change;
  338.   new_level = itos (shell_level);
  339.   bind_variable ("SHLVL", new_level);
  340.   free (new_level);
  341. }
  342.  
  343. /* Add NAME to the list of variables that cannot be unset
  344.    if it isn't already there. */
  345. non_unsettable (name)
  346.      char *name;
  347. {
  348.   register int i;
  349.  
  350.   if (!non_unsettable_vars)
  351.     {
  352.       non_unsettable_vars = (char **)xmalloc (1 * sizeof (char *));
  353.       non_unsettable_vars[0] = (char *)NULL;
  354.     }
  355.  
  356.   for (i = 0; non_unsettable_vars[i]; i++)
  357.     if (strcmp (non_unsettable_vars[i], name) == 0)
  358.       return;
  359.  
  360.   non_unsettable_vars = (char **)
  361.     xrealloc (non_unsettable_vars, (2 + i) * sizeof (char *));
  362.   non_unsettable_vars[i] = savestring (name);
  363.   non_unsettable_vars[i + 1] = (char *)NULL;
  364. }
  365.  
  366. /* Set NAME to VALUE if NAME has no value. */
  367. SHELL_VAR *
  368. set_if_not (name, value)
  369.      char *name, *value;
  370. {
  371.   SHELL_VAR *v = find_variable (name);
  372.  
  373.   if (!v)
  374.     v = bind_variable (name, value);
  375.   return (v);
  376. }
  377.  
  378. /* Map FUNCTION over the variables in VARIABLES.  Return an array of the
  379.    variables that satisfy FUNCTION.  Satisfy means that FUNCTION returns
  380.    a non-zero value for.  A NULL value for FUNCTION means to use all
  381.    variables. */
  382. SHELL_VAR **
  383. map_over (function, var_hash_table)
  384.      Function *function;
  385.      HASH_TABLE* var_hash_table;
  386. {
  387.   register int i;
  388.   register BUCKET_CONTENTS *tlist;
  389.   SHELL_VAR *var, **list = (SHELL_VAR **)NULL;
  390.   int list_index = 0, list_size = 0;
  391.  
  392.   for (i = 0; i < var_hash_table->nbuckets; i++)
  393.     {
  394.       tlist = get_hash_bucket (i, var_hash_table);
  395.  
  396.       while (tlist)
  397.     {
  398.       var = (SHELL_VAR *)tlist->data;
  399.  
  400.       if (!function || (*function) (var))
  401.         {
  402.           if (list_index + 1 >= list_size)
  403.         list = (SHELL_VAR **)
  404.           xrealloc (list, (list_size += 20) * sizeof (SHELL_VAR *));
  405.  
  406.           list[list_index++] = var;
  407.           list[list_index] = (SHELL_VAR *)NULL;
  408.         }
  409.       tlist = tlist->next;
  410.     }
  411.     }
  412.   return (list);
  413. }
  414.  
  415. int
  416. qsort_var_comp (var1, var2)
  417.      SHELL_VAR **var1, **var2;
  418. {
  419.   return (strcmp ((*var1)->name, (*var2)->name));
  420. }
  421.  
  422. sort_variables (array)
  423.      SHELL_VAR **array;
  424. {
  425.   qsort (array, array_len (array), sizeof (SHELL_VAR *), qsort_var_comp);
  426. }
  427.  
  428. /* Create a NULL terminated array of all the shell variables in TABLE. */
  429. static SHELL_VAR **
  430. all_vars (table)
  431.      HASH_TABLE *table;
  432. {
  433.   SHELL_VAR **list;
  434.  
  435.   list = map_over ((Function *)NULL, table);
  436.   if (list)
  437.     sort_variables (list);
  438.   return (list);
  439. }
  440.  
  441. /* Create a NULL terminated array of all the shell variables. */
  442. SHELL_VAR **
  443. all_shell_variables ()
  444. {
  445.   return (all_vars (shell_variables));
  446. }
  447.  
  448. /* Create a NULL terminated array of all the shell functions. */
  449. SHELL_VAR **
  450. all_shell_functions ()
  451. {
  452.   return (all_vars (shell_functions));
  453. }
  454.  
  455. /* Print VARS to stdout in such a way that they can be read back in. */
  456. print_var_list (list)
  457.      register SHELL_VAR **list;
  458. {
  459.   register int i;
  460.   register SHELL_VAR *var;
  461.  
  462.   for (i = 0; list && (var = list[i]); i++)
  463.     if (!invisible_p (var))
  464.       print_assignment (var);
  465. }
  466.  
  467. #if defined (NOTDEF)
  468. /* Print LIST (a linked list of shell variables) to stdout
  469.    by printing the names, without the values.  Used to support the
  470.    `set +' command. */
  471. print_vars_no_values (list)
  472.      register SHELL_VAR **list;
  473. {
  474.   register int i;
  475.   register SHELL_VAR *var;
  476.  
  477.   for (i = 0; list && (var = list[i]); i++)
  478.     if (!invisible_p (var))
  479.       printf ("%s\n", var->name);
  480. }
  481. #endif
  482.  
  483. /* Print the value of a single SHELL_VAR.  No newline is
  484.    output, but the variable is printed in such a way that
  485.    it can be read back in. */
  486. print_assignment (var)
  487.      SHELL_VAR *var;
  488. {
  489.   if (function_p (var) && var->value)
  490.     {
  491.       printf ("%s=", var->name);
  492.       print_var_function (var);
  493.       printf ("\n");
  494.     }
  495.   else if (var->value)
  496.     {
  497.       printf ("%s=", var->name);
  498.       print_var_value (var);
  499.       printf ("\n");
  500.     }
  501. }
  502.  
  503. /* Print the value cell of VAR, a shell variable.  Do not print
  504.    the name, nor leading/trailing newline. */
  505. print_var_value (var)
  506.      SHELL_VAR *var;
  507. {
  508.   if (var->value)
  509.     printf ("%s", var->value);
  510. }
  511.  
  512. /* Print the function cell of VAR, a shell variable.  Do not
  513.    print the name, nor leading/trailing newline. */
  514. print_var_function (var)
  515.      SHELL_VAR *var;
  516. {
  517.   char *named_function_string ();
  518.  
  519.   if (function_p (var) && var->value)
  520.     printf ("%s", named_function_string ((char *)NULL, var->value, 1));
  521. }
  522.  
  523.  
  524. /* **************************************************************** */
  525. /*                                                                  */
  526. /*                 Dynamic Variable Extension                       */
  527. /*                                                                  */
  528. /* **************************************************************** */
  529.  
  530. /* DYNAMIC VARIABLES
  531.    
  532.    These are variables whose values are generated anew each time they are
  533.    referenced.  These are implemented using a pair of function pointers
  534.    in the struct variable: assign_func, which is called from bind_variable,
  535.    and dynamic_value, which is called from find_variable.
  536.    
  537.    assign_func is called from bind_variable, if bind_variable discovers
  538.    that the variable being assigned to has such a function.  The function
  539.    is called as
  540.       SHELL_VAR *temp = (*(entry->assign_func)) (entry, value)
  541.    and the (SHELL_VAR *)temp is returned as the value of bind_variable.  It
  542.    is usually ENTRY (self).
  543.    
  544.    dynamic_value is called from find_variable to return a `new' value for
  545.    the specified dynamic varible.  If this function is NULL, the variable
  546.    is treated as a `normal' shell variable.  If it is not, however, then
  547.    this function is called like this:
  548.       tempvar = (*(var->dynamic_value)) (var);
  549.    
  550.    Sometimes `tempvar' will replace the value of `var'.  Other times, the
  551.    shell will simply use the string value.  Pretty object-oriented, huh?
  552.    
  553.    Be warned, though: if you `unset' a special variable, it loses its
  554.    special meaning, even if you subsequently set it.
  555.    
  556.    The special assignment code would probably have been better put in
  557.    subst.c: do_assignment, in the same style as
  558.    stupidly_hack_special_variables, but I wanted the changes as
  559.    localized as possible.  */
  560.  
  561. /* The value of $SECONDS.  This is the number of seconds since shell
  562.    invocation, or, the number of seconds since the last assignment + the
  563.    value of the last assignment. */
  564. static long seconds_value_assigned = (long)0;
  565.  
  566. /* Originally defined in shell.c */
  567. extern time_t shell_start_time;
  568.  
  569. SHELL_VAR *
  570. assign_seconds (self, value)
  571.      SHELL_VAR *self;
  572.      char *value;
  573. {
  574.   seconds_value_assigned = atol (value);
  575.   shell_start_time = NOW;
  576.   return (self);
  577. }
  578.  
  579. SHELL_VAR *
  580. get_seconds (var)
  581.      SHELL_VAR *var;
  582. {
  583.   extern char *itos ();
  584.   time_t time_since_start;
  585.   char *p;
  586.  
  587.   time_since_start = NOW - shell_start_time;
  588.   p = itos((int) seconds_value_assigned + time_since_start);
  589.  
  590.   if (var->value)
  591.     free (var->value);
  592.  
  593.   var->attributes |= att_integer;
  594.   var->value = p;
  595.   return (var);
  596. }
  597.  
  598. /* The random number seed.  You can change this by setting RANDOM. */
  599. static unsigned long rseed = 1;
  600.  
  601. /* A linear congruential random number generator based on the ANSI
  602.    C standard.  A more complicated one is overkill.  */
  603.  
  604. /* Returns a pseudo-random number between 0 and 32767. */
  605. static int
  606. brand ()
  607. {
  608.   rseed = rseed * 1103515245 + 12345;
  609.   return ((unsigned int)(rseed / 65536) % 32768);
  610. }
  611.  
  612. /* Set the random number generator seed to SEED. */
  613. static void
  614. sbrand (seed)
  615.      int seed;
  616. {
  617.   rseed = seed;
  618. }
  619.  
  620. static SHELL_VAR *
  621. assign_random (self, value)
  622.      SHELL_VAR *self;
  623.      char *value;
  624. {
  625.   int s = atoi (value);
  626.  
  627.   sbrand (s);
  628.   return (self);
  629. }
  630.  
  631. static SHELL_VAR *
  632. get_random (var)
  633.      SHELL_VAR *var;
  634. {
  635.   int rv;
  636.   char *p;
  637.   extern char *itos ();
  638.  
  639.   rv = brand ();
  640.   p = itos ((int)rv);
  641.   if (var->value)
  642.     free (var->value);
  643.  
  644.   var->attributes |= att_integer;
  645.   var->value = p;
  646.   return (var);
  647. }
  648.  
  649. /* Function which returns the current line number. */
  650. static SHELL_VAR *
  651. get_lineno (var)
  652.      SHELL_VAR *var;
  653. {
  654.   extern int line_number;
  655.   char *p;
  656.   extern char *itos ();
  657.  
  658.   p = itos (line_number);
  659.   if (var->value)
  660.     free (var->value);
  661.   var->value = p;
  662.   return (var);
  663. }
  664.  
  665. initialize_dynamic_variables ()
  666. {
  667.   SHELL_VAR *v;
  668.  
  669.   v = bind_variable ("SECONDS", (char *)NULL);
  670.   v->dynamic_value = get_seconds;
  671.   v->assign_func = assign_seconds;
  672.  
  673.   v = bind_variable ("RANDOM", (char *)NULL);
  674.   v->dynamic_value = get_random;
  675.   v->assign_func = assign_random;
  676.  
  677.   v = bind_variable ("LINENO", (char *)NULL);
  678.   v->dynamic_value = get_lineno;
  679.   v->assign_func = (DYNAMIC_FUNC *)NULL;
  680. }
  681.  
  682. /* How to get a pointer to the shell variable or function named NAME.
  683.    HASHED_VARS is a pointer to the hash table containing the list
  684.    of interest (either variables or functions). */
  685. SHELL_VAR *
  686. var_lookup (name, hashed_vars)
  687.      char *name;
  688.      HASH_TABLE *hashed_vars;
  689. {
  690.   BUCKET_CONTENTS *bucket;
  691.  
  692.   bucket = find_hash_item (name, hashed_vars);
  693.  
  694.   if (bucket)
  695.     return ((SHELL_VAR *)bucket->data);
  696.   else
  697.     return ((SHELL_VAR *)NULL);
  698. }
  699.  
  700. /* Look up the variable entry whose name matches STRING.
  701.    Returns the entry or NULL. */
  702. SHELL_VAR *
  703. find_variable (name)
  704.      char *name;
  705. {
  706.   extern int variable_context;
  707.   extern Function *this_shell_builtin;
  708.   SHELL_VAR *find_tempenv_variable ();
  709.   SHELL_VAR *var = (SHELL_VAR *)NULL;
  710.  
  711.   /* If we are executing a function or builtin, first look in the
  712.      temporary environment for the variable.  This allows constructs
  713.      such as "foo=x eval 'echo $foo'" to get the `exported' value
  714.      of $foo. */
  715.   if (variable_context || this_shell_builtin)
  716.     var = find_tempenv_variable (name);
  717.  
  718.   if (!var)
  719.     var = var_lookup (name, shell_variables);
  720.  
  721.   if (!var)
  722.     return ((SHELL_VAR *)NULL);
  723.  
  724.   if (var->dynamic_value)
  725.     return ((*(var->dynamic_value)) (var));
  726.   else
  727.     return (var);
  728. }
  729.  
  730. /* Look up the function entry whose name matches STRING.
  731.    Returns the entry or NULL. */
  732. SHELL_VAR *
  733. find_function (name)
  734.      char *name;
  735. {
  736.   return (var_lookup (name, shell_functions));
  737. }
  738.  
  739. /* Return the string value of a variable.  Return NULL if the variable
  740.    doesn't exist, or only has a function as a value.  Don't cons a new
  741.    string. */
  742. char *
  743. get_string_value (var_name)
  744.      char *var_name;
  745. {
  746.   SHELL_VAR *var = find_variable (var_name);
  747.  
  748.   if (!var)
  749.     return (char *)NULL;
  750.   else
  751.     return (var->value);
  752. }
  753.  
  754. /* Create a local variable referenced by NAME. */
  755. SHELL_VAR *
  756. make_local_variable (name)
  757.      char *name;
  758. {
  759.   SHELL_VAR *new_var, *old_var, *bind_variable ();
  760.   BUCKET_CONTENTS *elt;
  761.  
  762.   /* local foo; local foo;  is a no-op. */
  763.   old_var = find_variable (name);
  764.   if (old_var && old_var->context == variable_context)
  765.     return (old_var);
  766.  
  767.   elt = remove_hash_item (name, shell_variables);
  768.   if (elt)
  769.     {
  770.       old_var = (SHELL_VAR *)elt->data;
  771.       free (elt->key);
  772.       free (elt);
  773.     }
  774.   else
  775.     old_var = (SHELL_VAR *)NULL;
  776.  
  777.   /* If a variable does not already exist with this name, then
  778.      just make a new one. */
  779.   if (!old_var)
  780.     {
  781.       new_var = bind_variable (name, "");
  782.     }
  783.   else
  784.     {
  785.       new_var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  786.  
  787.       new_var->name = savestring (name);
  788.       new_var->value = savestring ("");
  789.  
  790.       new_var->dynamic_value = (DYNAMIC_FUNC *)NULL;
  791.       new_var->assign_func = (DYNAMIC_FUNC *)NULL;
  792.  
  793.       new_var->attributes = 0;
  794.  
  795.       if (exported_p (old_var))
  796.     new_var->attributes |= att_exported;
  797.  
  798.       new_var->prev_context = old_var;
  799.       elt = add_hash_item (savestring (name), shell_variables);
  800.       elt->data = (char *)new_var;
  801.     }
  802.  
  803.   new_var->context = variable_context;
  804.   return (new_var);
  805. }
  806.  
  807. /* Bind a variable NAME to VALUE.  This conses up the name
  808.    and value strings. */
  809. SHELL_VAR *
  810. bind_variable (name, value)
  811.      char *name, *value;
  812. {
  813.   SHELL_VAR *entry = var_lookup (name, shell_variables);
  814.  
  815.   if (!entry)
  816.     {
  817.       /* Make a new entry for this variable.  Then do the binding. */
  818.       entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  819.  
  820.       entry->attributes = 0;
  821.       entry->name = savestring (name);
  822.  
  823.       if (value)
  824.     entry->value = savestring (value);
  825.       else
  826.     entry->value = (char *)NULL;
  827.  
  828.       entry->dynamic_value = (DYNAMIC_FUNC *)NULL;
  829.       entry->assign_func = (DYNAMIC_FUNC *)NULL;
  830.  
  831.       /* Always assume variables are to be made at toplevel!
  832.      make_local_variable has the responsibilty of changing the
  833.      variable context. */
  834.       entry->context = 0;
  835.       entry->prev_context = (SHELL_VAR *)NULL;
  836.  
  837.       {
  838.     BUCKET_CONTENTS *elt;
  839.  
  840.     elt = add_hash_item (savestring (name), shell_variables);
  841.     elt->data = (char *)entry;
  842.       }
  843.     }
  844.   else if (entry->assign_func)
  845.     return ((*(entry->assign_func)) (entry, value));
  846.   else
  847.     {
  848.       if (readonly_p (entry))
  849.     {
  850.       report_error ("%s: read-only variable", name);
  851.       return (entry);
  852.     }
  853.  
  854.       /* If this variable has had its type set to integer (via `declare -i'),
  855.      then do expression evaluation on it and store the result.  The
  856.      functions in expr.c (evalexp and bind_int_variable) are responsible
  857.      for turning off the integer flag if they don't want further
  858.      evaluation done. */
  859.       if (integer_p (entry))
  860.     {
  861.       long val, evalexp();
  862.       extern char *itos();
  863.  
  864.       val = evalexp (value);
  865.       /* We cannot free () entry->value before this; what if the string
  866.          we are working is `even=even+2'?  We need the original value
  867.          around while we are doing the evaluation to handle any possible
  868.          recursion. */
  869.       if (entry->value)
  870.         free (entry->value);
  871.  
  872.       entry->value = itos (val);
  873.     }
  874.       else
  875.     {
  876.       if (entry->value)
  877.         free (entry->value);
  878.  
  879.       if (value)
  880.         entry->value = savestring (value);
  881.       else
  882.         entry->value = (char *)NULL;
  883.     }
  884.     }
  885.  
  886.   if (mark_modified_vars)
  887.     entry->attributes |= att_exported;
  888.  
  889.   if (exported_p (entry))
  890.     array_needs_making = 1;
  891.  
  892.   return (entry);
  893. }
  894.  
  895. /* Dispose of the information attached to VAR. */
  896. dispose_variable (var)
  897.      SHELL_VAR *var;
  898. {
  899.   if (!var)
  900.     return;
  901.  
  902.   if (function_p (var))
  903.     dispose_command (var->value);
  904.   else if (var->value)
  905.     free (var->value);
  906.  
  907.   free (var->name);
  908.  
  909.   if (exported_p (var))
  910.     array_needs_making = 1;
  911.  
  912.   free (var);
  913. }
  914.  
  915. /* Unset the variable referenced by NAME. */
  916. unbind_variable (name)
  917.      char *name;
  918. {
  919.   SHELL_VAR *var = find_variable (name);
  920.  
  921.   if (!var)
  922.     return (-1);
  923.  
  924.   if (var->value)
  925.     {
  926.       free (var->value);
  927.       var->value = (char *)NULL;
  928.     }
  929.  
  930.   makunbound (name, shell_variables);
  931.  
  932.   return (0);
  933. }
  934.  
  935. /* Make the variable associated with NAME go away.  HASH_LIST is the
  936.    hash table from which this variable should be deleted (either
  937.    shell_variables or shell_functions).
  938.    Returns non-zero if the variable couldn't be found. */
  939. makunbound (name, hash_list)
  940.      char *name;
  941.      HASH_TABLE *hash_list;
  942. {
  943.   BUCKET_CONTENTS *elt;
  944.   SHELL_VAR *old_var, *new_var;
  945.  
  946.   elt = remove_hash_item (name, hash_list);
  947.  
  948.   if (!elt)
  949.     return (-1);
  950.  
  951.   old_var = (SHELL_VAR *)elt->data;
  952.   new_var = old_var->prev_context;
  953.  
  954.   if (old_var && exported_p (old_var))
  955.     array_needs_making++;
  956.  
  957.   if (new_var)
  958.     {
  959.       /* Has to be a variable, functions don't have previous contexts. */
  960.       BUCKET_CONTENTS *new_elt;
  961.  
  962.       new_elt = add_hash_item (savestring (new_var->name), hash_list);
  963.       new_elt->data = (char *)new_var;
  964.  
  965.       if (exported_p (new_var))
  966.     set_var_auto_export (new_var->name);
  967.     }
  968.  
  969.   free (elt->key);
  970.   free (elt);
  971.  
  972.   dispose_variable (old_var);
  973.   stupidly_hack_special_variables (name);
  974.   return (0);
  975. }
  976.  
  977. /* Remove the variable with NAME if it is a local variable in the
  978.    current context. */
  979. kill_local_variable (name)
  980.      char *name;
  981. {
  982.   SHELL_VAR *temp = find_variable (name);
  983.  
  984.   if (temp && (temp->context == variable_context))
  985.     {
  986.       makunbound (name, shell_variables);
  987.       return (0);
  988.     }
  989.   return (-1);
  990. }
  991.  
  992. /* Get rid of all of the variables in the current context. */
  993. int
  994. variable_in_context (var)
  995.      SHELL_VAR *var;
  996. {
  997.   return (var && var->context == variable_context);
  998. }
  999.  
  1000. kill_all_local_variables ()
  1001. {
  1002.   register int i, pass;
  1003.   register SHELL_VAR *var, **list;
  1004.   HASH_TABLE *varlist;
  1005.  
  1006.   for (pass = 0; pass < 2; pass++)
  1007.     {
  1008.       varlist = pass ? shell_functions : shell_variables;
  1009.  
  1010.       list = map_over (variable_in_context, varlist);
  1011.  
  1012.       if (list)
  1013.     {
  1014.       for (i = 0; var = list[i]; i++)
  1015.         makunbound (var->name, varlist);
  1016.  
  1017.       free (list);
  1018.     }
  1019.     }
  1020. }
  1021.  
  1022. /* Delete the entire contents of the hash table. */
  1023. delete_all_variables (hashed_vars)
  1024.      HASH_TABLE *hashed_vars;
  1025. {
  1026.   register int i;
  1027.   register BUCKET_CONTENTS *bucket;
  1028.  
  1029.   for (i = 0; i < hashed_vars->nbuckets; i++)
  1030.     {
  1031.       bucket = hashed_vars->bucket_array[i];
  1032.  
  1033.       while (bucket)
  1034.     {
  1035.       BUCKET_CONTENTS *temp = bucket;
  1036.       SHELL_VAR *var, *prev;
  1037.  
  1038.       bucket = bucket->next;
  1039.  
  1040.       var = (SHELL_VAR *)temp->data;
  1041.  
  1042.       while (var)
  1043.         {
  1044.           prev = var->prev_context;
  1045.           dispose_variable (var);
  1046.  
  1047.           var = prev;
  1048.         }
  1049.  
  1050.       free (temp->key);
  1051.       free (temp);
  1052.     }
  1053.       hashed_vars->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
  1054.     }
  1055. }
  1056.  
  1057. SHELL_VAR *
  1058. new_shell_variable (name)
  1059.      char *name;
  1060. {
  1061.   SHELL_VAR *var;
  1062.  
  1063.   var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  1064.  
  1065.   bzero (var, sizeof (SHELL_VAR));
  1066.   var->name = savestring (name);
  1067.   return (var);
  1068. }
  1069.  
  1070. /* Do a function binding to a variable.  You pass the name and
  1071.    the command to bind to.  This conses the name and command. */
  1072. SHELL_VAR *
  1073. bind_function (name, value)
  1074.      char *name;
  1075.      COMMAND *value;
  1076. {
  1077.   SHELL_VAR *entry = find_function (name);
  1078.  
  1079.   if (!entry)
  1080.     {
  1081.       BUCKET_CONTENTS *elt;
  1082.  
  1083.       elt = add_hash_item (savestring (name), shell_functions);
  1084.  
  1085.       elt->data = (char *)new_shell_variable (name);
  1086.       entry = (SHELL_VAR *)elt->data;
  1087.       entry->dynamic_value = (DYNAMIC_FUNC *)NULL;
  1088.       entry->assign_func = (DYNAMIC_FUNC *)NULL;
  1089.  
  1090.       /* Functions are always made at the top level.  This allows a
  1091.      function to define another function (like autoload). */
  1092.       entry->context = 0;
  1093.     }
  1094.  
  1095.   if (entry->value)
  1096.     dispose_command (entry->value);
  1097.  
  1098.   if (value)    /* I don't think this can happen anymore */
  1099.     entry->value = (char *)copy_command (value);
  1100.   else
  1101.     entry->value = (char *)NULL;
  1102.  
  1103.   entry->attributes |= att_function;
  1104.  
  1105.   if (mark_modified_vars)
  1106.     entry->attributes |= att_exported;
  1107.  
  1108.   entry->attributes &= ~att_invisible;    /* Just to be sure */
  1109.  
  1110.   array_needs_making = 1;
  1111.  
  1112.   return (entry);
  1113. }
  1114.  
  1115. /* Copy VAR to a new data structure and return that structure. */
  1116. SHELL_VAR *
  1117. copy_variable (var)
  1118.      SHELL_VAR *var;
  1119. {
  1120.   SHELL_VAR *copy = (SHELL_VAR *)NULL;
  1121.  
  1122.   if (var)
  1123.     {
  1124.       copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  1125.  
  1126.       copy->attributes = var->attributes;
  1127.       copy->name = savestring (var->name);
  1128.  
  1129.       if (function_p (var))
  1130.     copy->value = (char *)copy_command (var->value);
  1131.       else if (var->value)
  1132.     copy->value = savestring (var->value);
  1133.       else
  1134.     copy->value = (char *)NULL;
  1135.  
  1136.       copy->dynamic_value = var->dynamic_value;
  1137.       copy->assign_func = var->assign_func;
  1138.  
  1139.       copy->context = var->context;
  1140.  
  1141.       /* Don't bother copying previous contexts along with this variable. */
  1142.       copy->prev_context = (SHELL_VAR *)NULL;
  1143.     }
  1144.   return (copy);
  1145. }
  1146.  
  1147. /* Make the variable associated with NAME be read-only.
  1148.    If NAME does not exist yet, create it. */
  1149. set_var_read_only (name)
  1150.      char *name;
  1151. {
  1152.   SHELL_VAR *entry = find_variable (name);
  1153.  
  1154.   if (!entry)
  1155.     {
  1156.       entry = bind_variable (name, "");
  1157.       if (!no_invisible_vars)
  1158.     entry->attributes |= att_invisible;
  1159.     }
  1160.   entry->attributes |= att_readonly;
  1161. }
  1162.  
  1163. /* Make the function associated with NAME be read-only.
  1164.    If NAME does not exist, we just punt, like auto_export code below. */
  1165. set_func_read_only (name)
  1166.      char *name;
  1167. {
  1168.   SHELL_VAR *entry = find_function (name);
  1169.  
  1170.   if (entry)
  1171.     entry->attributes |= att_readonly;
  1172. }
  1173.  
  1174. /* Make the variable associated with NAME be auto-exported.
  1175.    If NAME does not exist yet, create it. */
  1176. set_var_auto_export (name)
  1177.      char *name;
  1178. {
  1179.   SHELL_VAR *entry = find_variable (name);
  1180.  
  1181.   if (!entry)
  1182.     {
  1183.       entry = bind_variable (name, "");
  1184.       if (!no_invisible_vars)
  1185.     entry->attributes |= att_invisible;
  1186.     }
  1187.  
  1188.   set_auto_export (entry);
  1189. }
  1190.  
  1191. /* Make the function associated with NAME be auto-exported. */
  1192. set_func_auto_export (name)
  1193.      char *name;
  1194. {
  1195.   SHELL_VAR *entry = find_function (name);
  1196.  
  1197.   if (entry)
  1198.     {
  1199.       entry->attributes |= att_exported;
  1200.       array_needs_making = 1;
  1201.     }
  1202. }
  1203.  
  1204. /* Returns non-zero if STRING is an assignment statement.  The returned value
  1205.    is the index of the `=' sign. */
  1206. assignment (string)
  1207.      char *string;
  1208. {
  1209.   register int c, index = 0;
  1210.  
  1211.   c = string[index];
  1212.  
  1213.   if (!isletter (c) && c != '_')
  1214.     return (0);
  1215.  
  1216.   while (c = string[index])
  1217.     {
  1218.       /* The following is safe.  Note that '=' at the start of a word
  1219.      is not an assignment statement. */
  1220.       if (c == '=')
  1221.     return (index);
  1222.  
  1223.       if (!isletter (c) && !digit (c) && c != '_')
  1224.     return (0);
  1225.  
  1226.       index++;
  1227.     }
  1228.   return (0);
  1229. }
  1230.  
  1231. int
  1232. visible_var (var)
  1233.      SHELL_VAR *var;
  1234. {
  1235.   return (!invisible_p (var));
  1236. }
  1237.  
  1238. SHELL_VAR **
  1239. all_visible_variables ()
  1240. {
  1241.   SHELL_VAR **list;
  1242.  
  1243.   list = map_over (visible_var, shell_variables);
  1244.  
  1245.   if (list)
  1246.     sort_variables (list);
  1247.  
  1248.   return (list);
  1249. }
  1250.  
  1251. SHELL_VAR **
  1252. all_visible_functions ()
  1253. {
  1254.   SHELL_VAR **list;
  1255.  
  1256.   list = map_over (visible_var, shell_functions);
  1257.  
  1258.   if (list)
  1259.     sort_variables (list);
  1260.  
  1261.   return (list);
  1262. }
  1263.  
  1264. /* Return non-zero if the variable VAR is visible and exported. */
  1265. int
  1266. visible_and_exported (var)
  1267.      SHELL_VAR *var;
  1268. {
  1269.   return (!invisible_p (var) && exported_p (var));
  1270. }
  1271.  
  1272. /* Make an array of assignment statements from the hash table
  1273.    HASHED_VARS which contains SHELL_VARs.  Only visible, exported
  1274.    variables are eligible. */
  1275. char **
  1276. make_var_array (hashed_vars)
  1277.      HASH_TABLE *hashed_vars;
  1278. {
  1279.   register int i, list_index;
  1280.   register SHELL_VAR *var;
  1281.   char **list = (char **)NULL;
  1282.   SHELL_VAR **vars;
  1283.  
  1284.   vars = map_over (visible_and_exported, hashed_vars);
  1285.  
  1286.   if (!vars)
  1287.     return (char **)NULL;
  1288.  
  1289.   list = (char **)xmalloc ((1 + array_len ((char **)vars)) * sizeof (char *));
  1290.  
  1291.   for (i = 0, list_index = 0; var = vars[i]; i++)
  1292.     {
  1293.       char *value, *named_function_string ();
  1294.  
  1295.       if (function_p (var))
  1296.     {
  1297.       value =
  1298.         named_function_string ((char *)NULL,
  1299.                    (COMMAND *)function_cell (var), 0);
  1300.     }
  1301.       else
  1302.     value = value_cell (var);
  1303.  
  1304.       if (value)
  1305.     {
  1306. #if 0
  1307.       list[list_index] =
  1308.         (char *)xmalloc (2 + strlen (var->name) + strlen (value));
  1309.  
  1310.       sprintf (list[list_index], "%s=%s", var->name, value);
  1311. #else
  1312.       /* Let's see if this makes any kind of performance difference. */
  1313.       int name_len = strlen (var->name);
  1314.       int value_len = strlen (value);
  1315.       char    *p;
  1316.  
  1317.       p = list[list_index] =  (char *)xmalloc (2 + name_len + value_len);
  1318.       strcpy (p, var->name);
  1319.       p[name_len] = '=';
  1320.       strcpy (&p[name_len + 1], value);
  1321. #endif
  1322.       list_index++;
  1323.     }
  1324.     }
  1325.  
  1326.   free (vars);
  1327.   list[list_index] = (char *)NULL;
  1328.   return (list);
  1329. }
  1330.  
  1331. /* Add STRING to the array of foo=bar strings that we already
  1332.    have to add to the environment.  */
  1333. assign_in_env (string)
  1334.      char *string;
  1335. {
  1336.   int size;
  1337.  
  1338.   int offset = assignment (string);
  1339.   char *name = savestring (string);
  1340.   char *temp, *value = (char *)NULL;
  1341.  
  1342.   if (name[offset] == '=')
  1343.     {
  1344.       char *tilde_expand (), *string_list ();
  1345.       WORD_LIST *list, *expand_string_unsplit ();
  1346.  
  1347.       name[offset] = 0;
  1348.       temp = name + offset + 1;
  1349.       temp = tilde_expand (temp);
  1350.  
  1351.       list = expand_string_unsplit (temp, 0);
  1352.       value = string_list (list);
  1353.  
  1354.       if (list)
  1355.     dispose_words (list);
  1356.  
  1357.       free (temp);
  1358.     }
  1359.  
  1360.   if (!value) value = savestring ("");
  1361.  
  1362.   temp = (char *)xmalloc (2 + strlen (name) + strlen (value));
  1363.   sprintf (temp, "%s=%s", name, value);
  1364.   free (name);
  1365.  
  1366.   if (!temporary_env)
  1367.     {
  1368.       temporary_env = (char **)xmalloc (sizeof (char *));
  1369.       temporary_env [0] = (char *)NULL;
  1370.     }
  1371.  
  1372.   size = array_len (temporary_env);
  1373.   temporary_env = (char **)
  1374.     xrealloc (temporary_env, (size + 2) * (sizeof (char *)));
  1375.  
  1376.   temporary_env[size] = (temp);
  1377.   temporary_env[size + 1] = (char *)NULL;
  1378.   array_needs_making = 1;
  1379.  
  1380.   if (echo_command_at_execute)
  1381.     {
  1382.       /* The K*rn shell prints the `+ ' in front of assignment statements,
  1383.      so we do too. */
  1384.       extern char *indirection_level_string ();
  1385.       fprintf (stderr, "%s%s\n", indirection_level_string (), temp);
  1386.       fflush (stderr);
  1387.     }
  1388. }
  1389.  
  1390. /* Find a variable in the temporary environment that is named NAME.
  1391.    Return a consed variable, or NULL if not found. */
  1392. SHELL_VAR *
  1393. find_tempenv_variable (name)
  1394.      char *name;
  1395. {
  1396.   register int i, l = strlen (name);
  1397.  
  1398.   if (!temporary_env)
  1399.     return ((SHELL_VAR *)NULL);
  1400.  
  1401.   for (i = 0; temporary_env[i]; i++)
  1402.     {
  1403.       if (strncmp (temporary_env[i], name, l) == 0 &&
  1404.       temporary_env[i][l] == '=')
  1405.     {
  1406.       SHELL_VAR *temp;
  1407.  
  1408.       temp = new_shell_variable (name);
  1409.  
  1410.       if (temporary_env[i][l + 1])
  1411.         temp->value = savestring (&temporary_env[i][l + 1]);
  1412.       else
  1413.         temp->value = savestring ("");
  1414.       temp->attributes = att_exported;
  1415.       temp->context = 0;
  1416.       temp->prev_context = (SHELL_VAR *)NULL;
  1417.  
  1418.       temp->dynamic_value = (DYNAMIC_FUNC *)NULL;
  1419.       temp->assign_func = (DYNAMIC_FUNC *)NULL;
  1420.  
  1421.       return (temp);
  1422.     }
  1423.     }
  1424.   return ((SHELL_VAR *)NULL);
  1425. }
  1426.  
  1427. /* Free the storage used in the variable array for temporary
  1428.    environment variables. */
  1429. dispose_used_env_vars ()
  1430. {
  1431.   if (!temporary_env)
  1432.     return;
  1433.  
  1434.   free_array (temporary_env);
  1435.   temporary_env = (char **)NULL;
  1436.   array_needs_making = 1;
  1437. }
  1438.  
  1439. /* Stupid comparison routine for qsort () ing strings. */
  1440. int
  1441. qsort_string_compare (s1, s2)
  1442.      register char **s1, **s2;
  1443. {
  1444.   return (strcmp (*s1, *s2));
  1445. }
  1446.  
  1447. /* Sort ARRAY, a null terminated array of pointers to strings. */
  1448. sort_char_array (array)
  1449.      char **array;
  1450. {
  1451.   qsort (array, array_len (array), sizeof (char *), qsort_string_compare);
  1452. }
  1453.  
  1454. #define ISFUNC(s, o) ((s[o + 1] == '(')  && (s[o + 2] == ')'))
  1455.  
  1456. /* Add ASSIGN to ARRAY, or supercede a previous assignment in the
  1457.    array with the same left-hand side.  Return the new array. */
  1458. char **
  1459. add_or_supercede (assign, array)
  1460.      char *assign;
  1461.      register char **array;
  1462. {
  1463.   register int i;
  1464.   int equal_offset = assignment (assign);
  1465.  
  1466.   if (!equal_offset)
  1467.     return (array);
  1468.  
  1469.   /* If this is a function, then only supercede the function definition.
  1470.      We do this by including the `=(' in the comparison.  */
  1471.   if (assign[equal_offset + 1] == '(')
  1472.     equal_offset++;
  1473.  
  1474.   for (i = 0; array[i]; i++)
  1475.     {
  1476.       if (STREQN (assign, array[i], equal_offset + 1))
  1477.     {
  1478.       free (array[i]);
  1479.       array[i] = savestring (assign);
  1480.       return (array);
  1481.     }
  1482.     }
  1483.   array = (char **)xrealloc (array, ((2 + i) * sizeof (char *)));
  1484.   array[i++] = savestring (assign);
  1485.   array[i] = (char *)NULL;
  1486.   return (array);
  1487. }
  1488.  
  1489. /* Make the environment array for the command about to be executed.  If the
  1490.    array needs making.  Otherwise, do nothing.  If a shell action could
  1491.    change the array that commands receive for their environment, then the
  1492.    code should `array_needs_making++'. */
  1493. maybe_make_export_env ()
  1494. {
  1495.   register int i;
  1496.   register char **temp_array;
  1497.  
  1498.   if (array_needs_making)
  1499.     {
  1500.       if (export_env)
  1501.     free_array (export_env);
  1502.  
  1503. #ifdef SHADOWED_ENV
  1504.       export_env =
  1505.     (char **)xmalloc ((1 + array_len (shell_environment)) * sizeof (char *));
  1506.  
  1507.       for (i = 0; shell_environment[i]; i++)
  1508.     export_env[i] = savestring (shell_environment[i]);
  1509.       export_env[i] = (char *)NULL;
  1510.  
  1511. #else /* !SHADOWED_ENV */
  1512.  
  1513.       export_env = (char **)xmalloc (sizeof (char *));
  1514.       export_env[0] = (char *)NULL;
  1515.  
  1516. #endif /* SHADOWED_ENV */
  1517.  
  1518.       temp_array = make_var_array (shell_variables);
  1519.       for (i = 0; temp_array && temp_array[i]; i++)
  1520.     export_env = add_or_supercede (temp_array[i], export_env);
  1521.       free_array (temp_array);
  1522.  
  1523.       temp_array = make_var_array (shell_functions);
  1524.       for (i = 0; temp_array && temp_array[i]; i++)
  1525.     export_env = add_or_supercede (temp_array[i], export_env);
  1526.       free_array (temp_array);
  1527.  
  1528.       if (temporary_env)
  1529.     {
  1530.       for (i = 0; temporary_env[i]; i++)
  1531.         export_env = add_or_supercede (temporary_env[i], export_env);
  1532.  
  1533.       /* Sort the array alphabetically. */
  1534.       sort_char_array (export_env);
  1535.     }
  1536.       array_needs_making = 0;
  1537.     }
  1538. }
  1539.  
  1540. /* We always put _ in the environment as the name of this command. */
  1541. put_command_name_into_env (command_name)
  1542.      char *command_name;
  1543. {
  1544.   char *dummy;
  1545.  
  1546.   dummy = (char *)xmalloc (4 + strlen (command_name));
  1547.  
  1548.   /* These three statements replace a call to sprintf */
  1549.   dummy[0] = '_';
  1550.   dummy[1] = '=';
  1551.   strcpy (&dummy[2], command_name);
  1552.   export_env = add_or_supercede (dummy, export_env);
  1553.   free (dummy);
  1554. }
  1555.  
  1556. /* We supply our own version of getenv () because we want library
  1557.    routines to get the changed values of exported variables. */
  1558. char *last_tempenv_value = (char *)NULL;
  1559.  
  1560. /* The NeXT C library has getenv () defined and used in the same file.
  1561.    This screws our scheme.  However, Bash will run on the NeXT using
  1562.    the C library getenv (), since right now the only environment variable
  1563.    that we care about is HOME, and that is already defined.  */
  1564. #if defined (__STDC__)
  1565. #  define _CONST_HACK const
  1566. #else
  1567. #  define _CONST_HACK
  1568. #endif /* !__STDC__ */
  1569.  
  1570. #if !defined (NeXT)
  1571. char *
  1572. getenv (name)
  1573.      char _CONST_HACK *name;
  1574. {
  1575.   SHELL_VAR *var = find_tempenv_variable (name);
  1576.  
  1577.   if (var)
  1578.     {
  1579.       if (last_tempenv_value)
  1580.     free (last_tempenv_value);
  1581.  
  1582.       last_tempenv_value = savestring (value_cell (var));
  1583.       dispose_variable (var);
  1584.       return (last_tempenv_value);
  1585.     }
  1586.   else if (shell_variables)
  1587.     {
  1588.       var = find_variable (name);
  1589.       if (var && exported_p (var))
  1590.     return (value_cell (var));
  1591.     }
  1592.   else
  1593.     {
  1594.       register int i, len = strlen (name);
  1595.       extern char **environ;
  1596.  
  1597.       /* In some cases, s5r3 invokes getenv() before main(); BSD systems
  1598.          using gprof also exhibit this behavior.  This means that
  1599.          shell_variables will be 0 when this is invoked.  We look up the
  1600.      variable in the real environment in that case. */
  1601.  
  1602.       for (i = 0; environ[i]; i++)
  1603.     {
  1604.       if ((strncmp (environ[i], name, len) == 0) &&
  1605.           (environ[i][len] == '='))
  1606.         return (environ[i] + len + 1);
  1607.     }
  1608.     }
  1609.  
  1610.   return ((char *)NULL);
  1611. }
  1612. #endif /* NeXT */
  1613.