pastebin - collaborative debugging tool
eckelmann.kpaste.net RSS


quantron: Fix shell/bash environment with sane defaults
Posted by Anonymous on Mon 18th Nov 2019 10:52
raw | new post

  1. diff --git a/ptxdist/configs/ecu01/ptxconfig b/ptxdist/configs/ecu01/ptxconfig
  2. index a725eb0..0fd28b4 100644
  3. --- a/ptxdist/configs/ecu01/ptxconfig
  4. +++ b/ptxdist/configs/ecu01/ptxconfig
  5. @@ -261,7 +261,7 @@ PTXCONF_ROOTFS_HOSTS=y
  6.  PTXCONF_ROOTFS_ISSUE=y
  7.  # PTXCONF_ROOTFS_MODPROBE_CONF is not set
  8.  PTXCONF_ROOTFS_NSSWITCH_CONF=y
  9. -PTXCONF_ROOTFS_PROFILE=y
  10. +# PTXCONF_ROOTFS_PROFILE is not set
  11.  PTXCONF_ROOTFS_PROTOCOLS=y
  12.  PTXCONF_ROOTFS_RESOLV_FILE=y
  13.  # PTXCONF_ROOTFS_RESOLV_LINK is not set
  14. @@ -360,21 +360,35 @@ PTXCONF_BASH_ARITHMETIC_FOR=y
  15.  PTXCONF_BASH_ARRAY=y
  16.  PTXCONF_BASH_HISTORY=y
  17.  PTXCONF_BASH_BRACE=y
  18. +PTXCONF_BASH_CASEMODATTR=y
  19. +PTXCONF_BASH_CASEMODEXP=y
  20. +PTXCONF_BASH_CMDTIMING=y
  21.  PTXCONF_BASH_CONDITIONAL=y
  22. +PTXCONF_BASH_CONDITIONAL_REGEX=y
  23. +PTXCONF_BASH_COPROCESSES=y
  24. +# PTXCONF_BASH_DEBUGGER is not set
  25. +# PTXCONF_BASH_DIREXPDEFLT is not set
  26.  PTXCONF_BASH_DIRSTACK=y
  27. +PTXCONF_BASH_DISABLED_BUILDINS=y
  28. +PTXCONF_BASH_DPARAN_ARITH=y
  29.  PTXCONF_BASH_EXTPATTERN=y
  30. +PTXCONF_BASH_EXTPATTERN_DEFLT=y
  31. +# PTXCONF_BASH_GLOB_ASCIIRANGE_DEFLT is not set
  32.  PTXCONF_BASH_HELP=y
  33.  PTXCONF_BASH_CMDHISTORY=y
  34.  PTXCONF_BASH_JOBS=y
  35. +PTXCONF_BASH_MULTIBYTE=y
  36.  PTXCONF_BASH_PROCSUBST=y
  37. -PTXCONF_BASH_COMPLETION=y
  38. +# PTXCONF_BASH_BASHCOMPLETION is not set
  39.  PTXCONF_BASH_ESC=y
  40.  PTXCONF_BASH_EDIT=y
  41.  # PTXCONF_BASH_RESTRICTED is not set
  42.  # PTXCONF_BASH_SELECT is not set
  43. +# PTXCONF_BASH_SINGLE_HELPLINE is not set
  44.  # PTXCONF_BASH_GPROF is not set
  45.  PTXCONF_BASH_STATIC=y
  46.  # PTXCONF_BASH_CURSES is not set
  47. +# PTXCONF_BASH_SH is not set
  48.  # PTXCONF_BC is not set
  49.  PTXCONF_BUSYBOX=y
  50.  PTXCONF_BUSYBOX_TELNETD_STARTSCRIPT=y
  51. @@ -2028,7 +2042,8 @@ PTXCONF_NCURSES_TERMCAP=y
  52.  # PTXCONF_SLANG is not set
  53.  # PTXCONF_SPARSEHASH is not set
  54.  # PTXCONF_SQLITE is not set
  55. -# PTXCONF_TERMCAP is not set
  56. +PTXCONF_TERMCAP=y
  57. +PTXCONF_TERMCAP_TERMCAP=y
  58.  # PTXCONF_XERCES is not set
  59.  PTXCONF_ZLIB=y
  60.  # PTXCONF_ZLIB_STATIC is not set
  61. diff --git a/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc b/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc
  62. new file mode 100644
  63. index 0000000..1aa9e30
  64. --- /dev/null
  65. +++ b/ptxdist/local_src/ecu01-basicsys/etc/bash.bashrc
  66. @@ -0,0 +1,41 @@
  67. +#
  68. +# /etc/bash.bashrc - config file for *interactive* bash shells
  69. +#
  70. +# (this is sourced after profile scripts (/etc/profile and
  71. +# ~/.profile, but before config script ~/.bashrc))
  72. +#
  73. +# Note that /etc/profile and ~/.profile are ONLY sourced for
  74. +# *LOGIN* shells, while /etc/bash.bashrc and ~/.bashrc are sourced
  75. +# for all interactive bash shells
  76. +#
  77. +
  78. +printf $"# Running /etc/bash.bashrc ...\n"
  79. +
  80. +# /etc/profile.environment - config for sub-shells
  81. +#PS1="\\u@\\h:\\w "
  82. +PS1='\u \t : \w # '
  83. +PS2=" >"
  84. +PS4="+ "
  85. +
  86. +alias vim='vi'
  87. +alias l='ls -l'
  88. +alias ll='ls -al'
  89. +alias ..='cd ..'
  90. +alias ...='cd ../..'
  91. +alias md='mkdir'
  92. +alias rd='rmdir'
  93. +
  94. +# Quantron: persistent history file for bash shells
  95. +#
  96. +# (note that HIST* variables, including HISTFILE, are settings
  97. +# for interactive shells and therefore do not belong into
  98. +# /etc/profile or ~/.profile.
  99. +# It should also NOT be exportet to the environment since HISTFILE
  100. +# affects ksh/ksh93 and other POSIX(-like) shells, which use
  101. +# different history file formats)
  102. +#
  103. +# (this means ptxdist usage of HISTFILE in ptx-supplied
  104. +# /etc/profile is plain wrong)
  105. +HISTFILE='/var/dyn/bash_history'
  106. +
  107. +# EOF.
  108. diff --git a/ptxdist/local_src/ecu01-basicsys/etc/profile b/ptxdist/local_src/ecu01-basicsys/etc/profile
  109. new file mode 100644
  110. index 0000000..02fa716
  111. --- /dev/null
  112. +++ b/ptxdist/local_src/ecu01-basicsys/etc/profile
  113. @@ -0,0 +1,36 @@
  114. +#
  115. +# /etc/profile - config for profile shells
  116. +#
  117. +
  118. +printf "## Running /etc/profile ...\n"
  119. +
  120. +# do not set interactive shell properties like HISTFILE, PS1, PS2,
  121. +# ..., or aliases here.
  122. +# Such stuff belongs into the startup files for *interactive* shell
  123. +# sessions/etc/bash.bashrc or /etc/ksh.kshrc
  124. +
  125. +# This fixes the backspace when telnetting in.
  126. +if [ "$TERM" != "linux" ]; then
  127. +        stty erase ^H
  128. +fi
  129. +
  130. +
  131. +# Exec local profile
  132. +if [ -e "/etc/profile.local" ]; then
  133. +       printf "running /etc/profile.local\n"
  134. +       . /etc/profile.local
  135. +fi
  136. +
  137. +# bug: workaround for issue with bash4 where an interactive login
  138. +# shell does not source /etc/bash.bashrc & ~/.bashrc
  139. +# Ordering is wrong with this workaround, because /etc/profile and
  140. +# ~/.profile should be sourced before /etc/bash.bashrc and
  141. +# ~/.bashrc instead of somewhere in the middle as in this ugly
  142. +# workaround
  143. +if [[ "$-" == *i* ]] && [[ "$0" == *bash* ]] ; then
  144. +       [[ -r /etc/bash.bashrc ]] && source /etc/bash.bashrc
  145. +       [[ -r $HOME/.bashrc ]] && source $HOME/.bashrc
  146. +fi
  147. +
  148. +
  149. +# EOF.
  150. diff --git a/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch b/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
  151. new file mode 100644
  152. index 0000000..d9a187d
  153. --- /dev/null
  154. +++ b/ptxdist/patches/bash-4.3.30/0001-Bash-4.3-patch-31.patch
  155. @@ -0,0 +1,5467 @@
  156. +From: Chet Ramey <chet.ramey@case.edu>
  157. +Date: Thu, 15 Jan 2015 10:20:04 -0500
  158. +Subject: [PATCH] Bash-4.3 patch 31
  159. +
  160. +---
  161. + patchlevel.h     |    2 +-
  162. + subst.h          |    1 +
  163. + variables.c      |   32 +-
  164. + variables.c.orig | 5365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
  165. + 4 files changed, 5397 insertions(+), 3 deletions(-)
  166. + create mode 100644 variables.c.orig
  167. +
  168. +diff --git a/patchlevel.h b/patchlevel.h
  169. +index e5dde5245275..0ad46aafbdd9 100644
  170. +--- a/patchlevel.h
  171. ++++ b/patchlevel.h
  172. +@@ -25,6 +25,6 @@
  173. +    regexp `^#define[  ]*PATCHLEVEL', since that's what support/mkversion.sh
  174. +    looks for to find the patch level (for the sccs version string). */
  175. +
  176. +-#define PATCHLEVEL 30
  177. ++#define PATCHLEVEL 31
  178. +
  179. + #endif /* _PATCHLEVEL_H_ */
  180. +diff --git a/subst.h b/subst.h
  181. +index cedaf8b6b444..1c300ab96b04 100644
  182. +--- a/subst.h
  183. ++++ b/subst.h
  184. +@@ -47,6 +47,7 @@
  185. + #define ASS_MKASSOC   0x0004
  186. + #define ASS_MKGLOBAL  0x0008  /* force global assignment */
  187. + #define ASS_NAMEREF   0x0010  /* assigning to nameref variable */
  188. ++#define ASS_FROMREF   0x0020  /* assigning from value of nameref variable */
  189. +
  190. + /* Flags for the string extraction functions. */
  191. + #define SX_NOALLOC    0x0001  /* just skip; don't return substring */
  192. +diff --git a/variables.c b/variables.c
  193. +index 7c82710e0f0b..81b7877e32e8 100644
  194. +--- a/variables.c
  195. ++++ b/variables.c
  196. +@@ -2516,10 +2516,27 @@ bind_variable_internal (name, value, table, hflags, aflags)
  197. +      HASH_TABLE *table;
  198. +      int hflags, aflags;
  199. + {
  200. +-  char *newval;
  201. ++  char *newname, *newval;
  202. +   SHELL_VAR *entry;
  203. ++#if defined (ARRAY_VARS)
  204. ++  arrayind_t ind;
  205. ++  char *subp;
  206. ++  int sublen;
  207. ++#endif
  208. +
  209. ++  newname = 0;
  210. ++#if defined (ARRAY_VARS)
  211. ++  if ((aflags & ASS_FROMREF) && (hflags & HASH_NOSRCH) == 0 && valid_array_reference (name))
  212. ++    {
  213. ++      newname = array_variable_name (name, &subp, &sublen);
  214. ++      if (newname == 0)
  215. ++      return (SHELL_VAR *)NULL;       /* XXX */
  216. ++      entry = hash_lookup (newname, table);
  217. ++    }
  218. ++  else
  219. ++#endif
  220. +   entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
  221. ++
  222. +   /* Follow the nameref chain here if this is the global variables table */
  223. +   if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
  224. +     {
  225. +@@ -2550,6 +2567,16 @@ bind_variable_internal (name, value, table, hflags, aflags)
  226. +       var_setvalue (entry, make_variable_value (entry, value, 0));
  227. +       }
  228. +     }
  229. ++#if defined (ARRAY_VARS)
  230. ++  else if (entry == 0 && newname)
  231. ++    {
  232. ++      entry = make_new_array_variable (newname);      /* indexed array by default */
  233. ++      if (entry == 0)
  234. ++      return entry;
  235. ++      ind = array_expand_index (name, subp, sublen);
  236. ++      bind_array_element (entry, ind, value, aflags);
  237. ++    }
  238. ++#endif
  239. +   else if (entry == 0)
  240. +     {
  241. +       entry = make_new_variable (name, table);
  242. +@@ -2670,7 +2697,8 @@ bind_variable (name, value, flags)
  243. +                        normal. */
  244. +                     if (nameref_cell (nv) == 0)
  245. +                       return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
  246. +-                    return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
  247. ++                    /* XXX - bug here with ref=array[index] */
  248. ++                    return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags|ASS_FROMREF));
  249. +                   }
  250. +                 else
  251. +                   v = nv;
  252. +diff --git a/variables.c.orig b/variables.c.orig
  253. +new file mode 100644
  254. +index 000000000000..7c82710e0f0b
  255. +--- /dev/null
  256. ++++ b/variables.c.orig
  257. +@@ -0,0 +1,5365 @@
  258. ++/* variables.c -- Functions for hacking shell variables. */
  259. ++
  260. ++/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
  261. ++
  262. ++   This file is part of GNU Bash, the Bourne Again SHell.
  263. ++
  264. ++   Bash is free software: you can redistribute it and/or modify
  265. ++   it under the terms of the GNU General Public License as published by
  266. ++   the Free Software Foundation, either version 3 of the License, or
  267. ++   (at your option) any later version.
  268. ++
  269. ++   Bash is distributed in the hope that it will be useful,
  270. ++   but WITHOUT ANY WARRANTY; without even the implied warranty of
  271. ++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  272. ++   GNU General Public License for more details.
  273. ++
  274. ++   You should have received a copy of the GNU General Public License
  275. ++   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
  276. ++*/
  277. ++
  278. ++#include "config.h"
  279. ++
  280. ++#include "bashtypes.h"
  281. ++#include "posixstat.h"
  282. ++#include "posixtime.h"
  283. ++
  284. ++#if defined (__QNX__)
  285. ++#  if defined (__QNXNTO__)
  286. ++#    include <sys/netmgr.h>
  287. ++#  else
  288. ++#    include <sys/vc.h>
  289. ++#  endif /* !__QNXNTO__ */
  290. ++#endif /* __QNX__ */
  291. ++
  292. ++#if defined (HAVE_UNISTD_H)
  293. ++#  include <unistd.h>
  294. ++#endif
  295. ++
  296. ++#include <stdio.h>
  297. ++#include "chartypes.h"
  298. ++#if defined (HAVE_PWD_H)
  299. ++#  include <pwd.h>
  300. ++#endif
  301. ++#include "bashansi.h"
  302. ++#include "bashintl.h"
  303. ++
  304. ++#define NEED_XTRACE_SET_DECL
  305. ++
  306. ++#include "shell.h"
  307. ++#include "flags.h"
  308. ++#include "execute_cmd.h"
  309. ++#include "findcmd.h"
  310. ++#include "mailcheck.h"
  311. ++#include "input.h"
  312. ++#include "hashcmd.h"
  313. ++#include "pathexp.h"
  314. ++#include "alias.h"
  315. ++#include "jobs.h"
  316. ++
  317. ++#include "version.h"
  318. ++
  319. ++#include "builtins/getopt.h"
  320. ++#include "builtins/common.h"
  321. ++#include "builtins/builtext.h"
  322. ++
  323. ++#if defined (READLINE)
  324. ++#  include "bashline.h"
  325. ++#  include <readline/readline.h>
  326. ++#else
  327. ++#  include <tilde/tilde.h>
  328. ++#endif
  329. ++
  330. ++#if defined (HISTORY)
  331. ++#  include "bashhist.h"
  332. ++#  include <readline/history.h>
  333. ++#endif /* HISTORY */
  334. ++
  335. ++#if defined (PROGRAMMABLE_COMPLETION)
  336. ++#  include "pcomplete.h"
  337. ++#endif
  338. ++
  339. ++#define TEMPENV_HASH_BUCKETS  4       /* must be power of two */
  340. ++
  341. ++#define ifsname(s)    ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
  342. ++
  343. ++#define BASHFUNC_PREFIX               "BASH_FUNC_"
  344. ++#define BASHFUNC_PREFLEN      10      /* == strlen(BASHFUNC_PREFIX */
  345. ++#define BASHFUNC_SUFFIX               "%%"
  346. ++#define BASHFUNC_SUFFLEN      2       /* == strlen(BASHFUNC_SUFFIX) */
  347. ++
  348. ++extern char **environ;
  349. ++
  350. ++/* Variables used here and defined in other files. */
  351. ++extern int posixly_correct;
  352. ++extern int line_number, line_number_base;
  353. ++extern int subshell_environment, indirection_level, subshell_level;
  354. ++extern int build_version, patch_level;
  355. ++extern int expanding_redir;
  356. ++extern int last_command_exit_value;
  357. ++extern char *dist_version, *release_status;
  358. ++extern char *shell_name;
  359. ++extern char *primary_prompt, *secondary_prompt;
  360. ++extern char *current_host_name;
  361. ++extern sh_builtin_func_t *this_shell_builtin;
  362. ++extern SHELL_VAR *this_shell_function;
  363. ++extern char *the_printed_command_except_trap;
  364. ++extern char *this_command_name;
  365. ++extern char *command_execution_string;
  366. ++extern time_t shell_start_time;
  367. ++extern int assigning_in_environment;
  368. ++extern int executing_builtin;
  369. ++extern int funcnest_max;
  370. ++
  371. ++#if defined (READLINE)
  372. ++extern int no_line_editing;
  373. ++extern int perform_hostname_completion;
  374. ++#endif
  375. ++
  376. ++/* The list of shell variables that the user has created at the global
  377. ++   scope, or that came from the environment. */
  378. ++VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
  379. ++
  380. ++/* The current list of shell variables, including function scopes */
  381. ++VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
  382. ++
  383. ++/* The list of shell functions that the user has created, or that came from
  384. ++   the environment. */
  385. ++HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
  386. ++
  387. ++#if defined (DEBUGGER)
  388. ++/* The table of shell function definitions that the user defined or that
  389. ++   came from the environment. */
  390. ++HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
  391. ++#endif
  392. ++
  393. ++/* The current variable context.  This is really a count of how deep into
  394. ++   executing functions we are. */
  395. ++int variable_context = 0;
  396. ++
  397. ++/* The set of shell assignments which are made only in the environment
  398. ++   for a single command. */
  399. ++HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
  400. ++
  401. ++/* Set to non-zero if an assignment error occurs while putting variables
  402. ++   into the temporary environment. */
  403. ++int tempenv_assign_error;
  404. ++
  405. ++/* Some funky variables which are known about specially.  Here is where
  406. ++   "$*", "$1", and all the cruft is kept. */
  407. ++char *dollar_vars[10];
  408. ++WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
  409. ++
  410. ++/* The value of $$. */
  411. ++pid_t dollar_dollar_pid;
  412. ++
  413. ++/* Non-zero means that we have to remake EXPORT_ENV. */
  414. ++int array_needs_making = 1;
  415. ++
  416. ++/* The number of times BASH has been executed.  This is set
  417. ++   by initialize_variables (). */
  418. ++int shell_level = 0;
  419. ++
  420. ++/* An array which is passed to commands as their environment.  It is
  421. ++   manufactured from the union of the initial environment and the
  422. ++   shell variables that are marked for export. */
  423. ++char **export_env = (char **)NULL;
  424. ++static int export_env_index;
  425. ++static int export_env_size;
  426. ++
  427. ++#if defined (READLINE)
  428. ++static int winsize_assignment;                /* currently assigning to LINES or COLUMNS */
  429. ++#endif
  430. ++
  431. ++static HASH_TABLE *last_table_searched;       /* hash_lookup sets this */
  432. ++
  433. ++/* Some forward declarations. */
  434. ++static void create_variable_tables __P((void));
  435. ++
  436. ++static void set_machine_vars __P((void));
  437. ++static void set_home_var __P((void));
  438. ++static void set_shell_var __P((void));
  439. ++static char *get_bash_name __P((void));
  440. ++static void initialize_shell_level __P((void));
  441. ++static void uidset __P((void));
  442. ++#if defined (ARRAY_VARS)
  443. ++static void make_vers_array __P((void));
  444. ++#endif
  445. ++
  446. ++static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
  447. ++#if defined (ARRAY_VARS)
  448. ++static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
  449. ++#endif
  450. ++static SHELL_VAR *get_self __P((SHELL_VAR *));
  451. ++
  452. ++#if defined (ARRAY_VARS)
  453. ++static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
  454. ++static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
  455. ++#endif
  456. ++
  457. ++static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
  458. ++static SHELL_VAR *get_seconds __P((SHELL_VAR *));
  459. ++static SHELL_VAR *init_seconds_var __P((void));
  460. ++
  461. ++static int brand __P((void));
  462. ++static void sbrand __P((unsigned long));              /* set bash random number generator. */
  463. ++static void seedrand __P((void));                     /* seed generator randomly */
  464. ++static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
  465. ++static SHELL_VAR *get_random __P((SHELL_VAR *));
  466. ++
  467. ++static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
  468. ++static SHELL_VAR *get_lineno __P((SHELL_VAR *));
  469. ++
  470. ++static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
  471. ++static SHELL_VAR *get_subshell __P((SHELL_VAR *));
  472. ++
  473. ++static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
  474. ++
  475. ++#if defined (HISTORY)
  476. ++static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
  477. ++#endif
  478. ++
  479. ++#if defined (READLINE)
  480. ++static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
  481. ++static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
  482. ++#endif
  483. ++
  484. ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  485. ++static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
  486. ++static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
  487. ++#endif
  488. ++
  489. ++#if defined (ARRAY_VARS)
  490. ++static SHELL_VAR *get_groupset __P((SHELL_VAR *));
  491. ++
  492. ++static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
  493. ++static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
  494. ++static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *,  char *, arrayind_t, char *));
  495. ++#  if defined (ALIAS)
  496. ++static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
  497. ++static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
  498. ++static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *,  char *, arrayind_t, char *));
  499. ++#  endif
  500. ++#endif
  501. ++
  502. ++static SHELL_VAR *get_funcname __P((SHELL_VAR *));
  503. ++static SHELL_VAR *init_funcname_var __P((void));
  504. ++
  505. ++static void initialize_dynamic_variables __P((void));
  506. ++
  507. ++static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
  508. ++static SHELL_VAR *new_shell_variable __P((const char *));
  509. ++static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
  510. ++static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
  511. ++
  512. ++static void dispose_variable_value __P((SHELL_VAR *));
  513. ++static void free_variable_hash_data __P((PTR_T));
  514. ++
  515. ++static VARLIST *vlist_alloc __P((int));
  516. ++static VARLIST *vlist_realloc __P((VARLIST *, int));
  517. ++static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
  518. ++
  519. ++static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
  520. ++
  521. ++static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
  522. ++
  523. ++static SHELL_VAR **vapply __P((sh_var_map_func_t *));
  524. ++static SHELL_VAR **fapply __P((sh_var_map_func_t *));
  525. ++
  526. ++static int visible_var __P((SHELL_VAR *));
  527. ++static int visible_and_exported __P((SHELL_VAR *));
  528. ++static int export_environment_candidate __P((SHELL_VAR *));
  529. ++static int local_and_exported __P((SHELL_VAR *));
  530. ++static int variable_in_context __P((SHELL_VAR *));
  531. ++#if defined (ARRAY_VARS)
  532. ++static int visible_array_vars __P((SHELL_VAR *));
  533. ++#endif
  534. ++
  535. ++static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
  536. ++static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
  537. ++static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
  538. ++
  539. ++static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
  540. ++static void push_temp_var __P((PTR_T));
  541. ++static void propagate_temp_var __P((PTR_T));
  542. ++static void dispose_temporary_env __P((sh_free_func_t *));    
  543. ++
  544. ++static inline char *mk_env_string __P((const char *, const char *, int));
  545. ++static char **make_env_array_from_var_list __P((SHELL_VAR **));
  546. ++static char **make_var_export_array __P((VAR_CONTEXT *));
  547. ++static char **make_func_export_array __P((void));
  548. ++static void add_temp_array_to_env __P((char **, int, int));
  549. ++
  550. ++static int n_shell_variables __P((void));
  551. ++static int set_context __P((SHELL_VAR *));
  552. ++
  553. ++static void push_func_var __P((PTR_T));
  554. ++static void push_exported_var __P((PTR_T));
  555. ++
  556. ++static inline int find_special_var __P((const char *));
  557. ++
  558. ++static void
  559. ++create_variable_tables ()
  560. ++{
  561. ++  if (shell_variables == 0)
  562. ++    {
  563. ++      shell_variables = global_variables = new_var_context ((char *)NULL, 0);
  564. ++      shell_variables->scope = 0;
  565. ++      shell_variables->table = hash_create (0);
  566. ++    }
  567. ++
  568. ++  if (shell_functions == 0)
  569. ++    shell_functions = hash_create (0);
  570. ++
  571. ++#if defined (DEBUGGER)
  572. ++  if (shell_function_defs == 0)
  573. ++    shell_function_defs = hash_create (0);
  574. ++#endif
  575. ++}
  576. ++
  577. ++/* Initialize the shell variables from the current environment.
  578. ++   If PRIVMODE is nonzero, don't import functions from ENV or
  579. ++   parse $SHELLOPTS. */
  580. ++void
  581. ++initialize_shell_variables (env, privmode)
  582. ++     char **env;
  583. ++     int privmode;
  584. ++{
  585. ++  char *name, *string, *temp_string;
  586. ++  int c, char_index, string_index, string_length, ro;
  587. ++  SHELL_VAR *temp_var;
  588. ++
  589. ++  create_variable_tables ();
  590. ++
  591. ++  for (string_index = 0; string = env[string_index++]; )
  592. ++    {
  593. ++      char_index = 0;
  594. ++      name = string;
  595. ++      while ((c = *string++) && c != '=')
  596. ++      ;
  597. ++      if (string[-1] == '=')
  598. ++      char_index = string - name - 1;
  599. ++
  600. ++      /* If there are weird things in the environment, like `=xxx' or a
  601. ++       string without an `=', just skip them. */
  602. ++      if (char_index == 0)
  603. ++      continue;
  604. ++
  605. ++      /* ASSERT(name[char_index] == '=') */
  606. ++      name[char_index] = '\0';
  607. ++      /* Now, name = env variable name, string = env variable value, and
  608. ++       char_index == strlen (name) */
  609. ++
  610. ++      temp_var = (SHELL_VAR *)NULL;
  611. ++
  612. ++      /* If exported function, define it now.  Don't import functions from
  613. ++       the environment in privileged mode. */
  614. ++      if (privmode == 0 && read_but_dont_execute == 0 &&
  615. ++          STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
  616. ++          STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
  617. ++        STREQN ("() {", string, 4))
  618. ++      {
  619. ++        size_t namelen;
  620. ++        char *tname;          /* desired imported function name */
  621. ++
  622. ++        namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
  623. ++
  624. ++        tname = name + BASHFUNC_PREFLEN;      /* start of func name */
  625. ++        tname[namelen] = '\0';                /* now tname == func name */
  626. ++
  627. ++        string_length = strlen (string);
  628. ++        temp_string = (char *)xmalloc (namelen + string_length + 2);
  629. ++
  630. ++        memcpy (temp_string, tname, namelen);
  631. ++        temp_string[namelen] = ' ';
  632. ++        memcpy (temp_string + namelen + 1, string, string_length + 1);
  633. ++
  634. ++        /* Don't import function names that are invalid identifiers from the
  635. ++           environment, though we still allow them to be defined as shell
  636. ++           variables. */
  637. ++        if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
  638. ++          parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
  639. ++
  640. ++        if (temp_var = find_function (tname))
  641. ++          {
  642. ++            VSETATTR (temp_var, (att_exported|att_imported));
  643. ++            array_needs_making = 1;
  644. ++          }
  645. ++        else
  646. ++          {
  647. ++            if (temp_var = bind_variable (name, string, 0))
  648. ++              {
  649. ++                VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
  650. ++                array_needs_making = 1;
  651. ++              }
  652. ++            last_command_exit_value = 1;
  653. ++            report_error (_("error importing function definition for `%s'"), tname);
  654. ++          }
  655. ++
  656. ++        /* Restore original suffix */
  657. ++        tname[namelen] = BASHFUNC_SUFFIX[0];
  658. ++      }
  659. ++#if defined (ARRAY_VARS)
  660. ++#  if ARRAY_EXPORT
  661. ++      /* Array variables may not yet be exported. */
  662. ++      else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
  663. ++      {
  664. ++        string_length = 1;
  665. ++        temp_string = extract_array_assignment_list (string, &string_length);
  666. ++        temp_var = assign_array_from_string (name, temp_string);
  667. ++        FREE (temp_string);
  668. ++        VSETATTR (temp_var, (att_exported | att_imported));
  669. ++        array_needs_making = 1;
  670. ++      }
  671. ++#  endif /* ARRAY_EXPORT */
  672. ++#endif
  673. ++#if 0
  674. ++      else if (legal_identifier (name))
  675. ++#else
  676. ++      else
  677. ++#endif
  678. ++      {
  679. ++        ro = 0;
  680. ++        if (posixly_correct && STREQ (name, "SHELLOPTS"))
  681. ++          {
  682. ++            temp_var = find_variable ("SHELLOPTS");
  683. ++            ro = temp_var && readonly_p (temp_var);
  684. ++            if (temp_var)
  685. ++              VUNSETATTR (temp_var, att_readonly);
  686. ++          }
  687. ++        temp_var = bind_variable (name, string, 0);
  688. ++        if (temp_var)
  689. ++          {
  690. ++            if (legal_identifier (name))
  691. ++              VSETATTR (temp_var, (att_exported | att_imported));
  692. ++            else
  693. ++              VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
  694. ++            if (ro)
  695. ++              VSETATTR (temp_var, att_readonly);
  696. ++            array_needs_making = 1;
  697. ++          }
  698. ++      }
  699. ++
  700. ++      name[char_index] = '=';
  701. ++      /* temp_var can be NULL if it was an exported function with a syntax
  702. ++       error (a different bug, but it still shouldn't dump core). */
  703. ++      if (temp_var && function_p (temp_var) == 0)     /* XXX not yet */
  704. ++      {
  705. ++        CACHE_IMPORTSTR (temp_var, name);
  706. ++      }
  707. ++    }
  708. ++
  709. ++  set_pwd ();
  710. ++
  711. ++  /* Set up initial value of $_ */
  712. ++  temp_var = set_if_not ("_", dollar_vars[0]);
  713. ++
  714. ++  /* Remember this pid. */
  715. ++  dollar_dollar_pid = getpid ();
  716. ++
  717. ++  /* Now make our own defaults in case the vars that we think are
  718. ++     important are missing. */
  719. ++  temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
  720. ++#if 0
  721. ++  set_auto_export (temp_var); /* XXX */
  722. ++#endif
  723. ++
  724. ++  temp_var = set_if_not ("TERM", "dumb");
  725. ++#if 0
  726. ++  set_auto_export (temp_var); /* XXX */
  727. ++#endif
  728. ++
  729. ++#if defined (__QNX__)
  730. ++  /* set node id -- don't import it from the environment */
  731. ++  {
  732. ++    char node_name[22];
  733. ++#  if defined (__QNXNTO__)
  734. ++    netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
  735. ++#  else
  736. ++    qnx_nidtostr (getnid (), node_name, sizeof (node_name));
  737. ++#  endif
  738. ++    temp_var = bind_variable ("NODE", node_name, 0);
  739. ++    set_auto_export (temp_var);
  740. ++  }
  741. ++#endif
  742. ++
  743. ++  /* set up the prompts. */
  744. ++  if (interactive_shell)
  745. ++    {
  746. ++#if defined (PROMPT_STRING_DECODE)
  747. ++      set_if_not ("PS1", primary_prompt);
  748. ++#else
  749. ++      if (current_user.uid == -1)
  750. ++      get_current_user_info ();
  751. ++      set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
  752. ++#endif
  753. ++      set_if_not ("PS2", secondary_prompt);
  754. ++    }
  755. ++  set_if_not ("PS4", "+ ");
  756. ++
  757. ++  /* Don't allow IFS to be imported from the environment. */
  758. ++  temp_var = bind_variable ("IFS", " \t\n", 0);
  759. ++  setifs (temp_var);
  760. ++
  761. ++  /* Magic machine types.  Pretty convenient. */
  762. ++  set_machine_vars ();
  763. ++
  764. ++  /* Default MAILCHECK for interactive shells.  Defer the creation of a
  765. ++     default MAILPATH until the startup files are read, because MAIL
  766. ++     names a mail file if MAILPATH is not set, and we should provide a
  767. ++     default only if neither is set. */
  768. ++  if (interactive_shell)
  769. ++    {
  770. ++      temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
  771. ++      VSETATTR (temp_var, att_integer);
  772. ++    }
  773. ++
  774. ++  /* Do some things with shell level. */
  775. ++  initialize_shell_level ();
  776. ++
  777. ++  set_ppid ();
  778. ++
  779. ++  /* Initialize the `getopts' stuff. */
  780. ++  temp_var = bind_variable ("OPTIND", "1", 0);
  781. ++  VSETATTR (temp_var, att_integer);
  782. ++  getopts_reset (0);
  783. ++  bind_variable ("OPTERR", "1", 0);
  784. ++  sh_opterr = 1;
  785. ++
  786. ++  if (login_shell == 1 && posixly_correct == 0)
  787. ++    set_home_var ();
  788. ++
  789. ++  /* Get the full pathname to THIS shell, and set the BASH variable
  790. ++     to it. */
  791. ++  name = get_bash_name ();
  792. ++  temp_var = bind_variable ("BASH", name, 0);
  793. ++  free (name);
  794. ++
  795. ++  /* Make the exported environment variable SHELL be the user's login
  796. ++     shell.  Note that the `tset' command looks at this variable
  797. ++     to determine what style of commands to output; if it ends in "csh",
  798. ++     then C-shell commands are output, else Bourne shell commands. */
  799. ++  set_shell_var ();
  800. ++
  801. ++  /* Make a variable called BASH_VERSION which contains the version info. */
  802. ++  bind_variable ("BASH_VERSION", shell_version_string (), 0);
  803. ++#if defined (ARRAY_VARS)
  804. ++  make_vers_array ();
  805. ++#endif
  806. ++
  807. ++  if (command_execution_string)
  808. ++    bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
  809. ++
  810. ++  /* Find out if we're supposed to be in Posix.2 mode via an
  811. ++     environment variable. */
  812. ++  temp_var = find_variable ("POSIXLY_CORRECT");
  813. ++  if (!temp_var)
  814. ++    temp_var = find_variable ("POSIX_PEDANTIC");
  815. ++  if (temp_var && imported_p (temp_var))
  816. ++    sv_strict_posix (temp_var->name);
  817. ++
  818. ++#if defined (HISTORY)
  819. ++  /* Set history variables to defaults, and then do whatever we would
  820. ++     do if the variable had just been set.  Do this only in the case
  821. ++     that we are remembering commands on the history list. */
  822. ++  if (remember_on_history)
  823. ++    {
  824. ++      name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
  825. ++
  826. ++      set_if_not ("HISTFILE", name);
  827. ++      free (name);
  828. ++    }
  829. ++#endif /* HISTORY */
  830. ++
  831. ++  /* Seed the random number generator. */
  832. ++  seedrand ();
  833. ++
  834. ++  /* Handle some "special" variables that we may have inherited from a
  835. ++     parent shell. */
  836. ++  if (interactive_shell)
  837. ++    {
  838. ++      temp_var = find_variable ("IGNOREEOF");
  839. ++      if (!temp_var)
  840. ++      temp_var = find_variable ("ignoreeof");
  841. ++      if (temp_var && imported_p (temp_var))
  842. ++      sv_ignoreeof (temp_var->name);
  843. ++    }
  844. ++
  845. ++#if defined (HISTORY)
  846. ++  if (interactive_shell && remember_on_history)
  847. ++    {
  848. ++      sv_history_control ("HISTCONTROL");
  849. ++      sv_histignore ("HISTIGNORE");
  850. ++      sv_histtimefmt ("HISTTIMEFORMAT");
  851. ++    }
  852. ++#endif /* HISTORY */
  853. ++
  854. ++#if defined (READLINE) && defined (STRICT_POSIX)
  855. ++  /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
  856. ++     -DSTRICT_POSIX */
  857. ++  if (interactive_shell && posixly_correct && no_line_editing == 0)
  858. ++    rl_prefer_env_winsize = 1;
  859. ++#endif /* READLINE && STRICT_POSIX */
  860. ++
  861. ++     /*
  862. ++      * 24 October 2001
  863. ++      *
  864. ++      * I'm tired of the arguing and bug reports.  Bash now leaves SSH_CLIENT
  865. ++      * and SSH2_CLIENT alone.  I'm going to rely on the shell_level check in
  866. ++      * isnetconn() to avoid running the startup files more often than wanted.
  867. ++      * That will, of course, only work if the user's login shell is bash, so
  868. ++      * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
  869. ++      * in config-top.h.
  870. ++      */
  871. ++#if 0
  872. ++  temp_var = find_variable ("SSH_CLIENT");
  873. ++  if (temp_var && imported_p (temp_var))
  874. ++    {
  875. ++      VUNSETATTR (temp_var, att_exported);
  876. ++      array_needs_making = 1;
  877. ++    }
  878. ++  temp_var = find_variable ("SSH2_CLIENT");
  879. ++  if (temp_var && imported_p (temp_var))
  880. ++    {
  881. ++      VUNSETATTR (temp_var, att_exported);
  882. ++      array_needs_making = 1;
  883. ++    }
  884. ++#endif
  885. ++
  886. ++  /* Get the user's real and effective user ids. */
  887. ++  uidset ();
  888. ++
  889. ++  temp_var = find_variable ("BASH_XTRACEFD");
  890. ++  if (temp_var && imported_p (temp_var))
  891. ++    sv_xtracefd (temp_var->name);
  892. ++
  893. ++  /* Initialize the dynamic variables, and seed their values. */
  894. ++  initialize_dynamic_variables ();
  895. ++}
  896. ++
  897. ++/* **************************************************************** */
  898. ++/*                                                                */
  899. ++/*         Setting values for special shell variables             */
  900. ++/*                                                                */
  901. ++/* **************************************************************** */
  902. ++
  903. ++static void
  904. ++set_machine_vars ()
  905. ++{
  906. ++  SHELL_VAR *temp_var;
  907. ++
  908. ++  temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
  909. ++  temp_var = set_if_not ("OSTYPE", OSTYPE);
  910. ++  temp_var = set_if_not ("MACHTYPE", MACHTYPE);
  911. ++
  912. ++  temp_var = set_if_not ("HOSTNAME", current_host_name);
  913. ++}
  914. ++
  915. ++/* Set $HOME to the information in the password file if we didn't get
  916. ++   it from the environment. */
  917. ++
  918. ++/* This function is not static so the tilde and readline libraries can
  919. ++   use it. */
  920. ++char *
  921. ++sh_get_home_dir ()
  922. ++{
  923. ++  if (current_user.home_dir == 0)
  924. ++    get_current_user_info ();
  925. ++  return current_user.home_dir;
  926. ++}
  927. ++
  928. ++static void
  929. ++set_home_var ()
  930. ++{
  931. ++  SHELL_VAR *temp_var;
  932. ++
  933. ++  temp_var = find_variable ("HOME");
  934. ++  if (temp_var == 0)
  935. ++    temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
  936. ++#if 0
  937. ++  VSETATTR (temp_var, att_exported);
  938. ++#endif
  939. ++}
  940. ++
  941. ++/* Set $SHELL to the user's login shell if it is not already set.  Call
  942. ++   get_current_user_info if we haven't already fetched the shell. */
  943. ++static void
  944. ++set_shell_var ()
  945. ++{
  946. ++  SHELL_VAR *temp_var;
  947. ++
  948. ++  temp_var = find_variable ("SHELL");
  949. ++  if (temp_var == 0)
  950. ++    {
  951. ++      if (current_user.shell == 0)
  952. ++      get_current_user_info ();
  953. ++      temp_var = bind_variable ("SHELL", current_user.shell, 0);
  954. ++    }
  955. ++#if 0
  956. ++  VSETATTR (temp_var, att_exported);
  957. ++#endif
  958. ++}
  959. ++
  960. ++static char *
  961. ++get_bash_name ()
  962. ++{
  963. ++  char *name;
  964. ++
  965. ++  if ((login_shell == 1) && RELPATH(shell_name))
  966. ++    {
  967. ++      if (current_user.shell == 0)
  968. ++      get_current_user_info ();
  969. ++      name = savestring (current_user.shell);
  970. ++    }
  971. ++  else if (ABSPATH(shell_name))
  972. ++    name = savestring (shell_name);
  973. ++  else if (shell_name[0] == '.' && shell_name[1] == '/')
  974. ++    {
  975. ++      /* Fast path for common case. */
  976. ++      char *cdir;
  977. ++      int len;
  978. ++
  979. ++      cdir = get_string_value ("PWD");
  980. ++      if (cdir)
  981. ++      {
  982. ++        len = strlen (cdir);
  983. ++        name = (char *)xmalloc (len + strlen (shell_name) + 1);
  984. ++        strcpy (name, cdir);
  985. ++        strcpy (name + len, shell_name + 1);
  986. ++      }
  987. ++      else
  988. ++      name = savestring (shell_name);
  989. ++    }
  990. ++  else
  991. ++    {
  992. ++      char *tname;
  993. ++      int s;
  994. ++
  995. ++      tname = find_user_command (shell_name);
  996. ++
  997. ++      if (tname == 0)
  998. ++      {
  999. ++        /* Try the current directory.  If there is not an executable
  1000. ++           there, just punt and use the login shell. */
  1001. ++        s = file_status (shell_name);
  1002. ++        if (s & FS_EXECABLE)
  1003. ++          {
  1004. ++            tname = make_absolute (shell_name, get_string_value ("PWD"));
  1005. ++            if (*shell_name == '.')
  1006. ++              {
  1007. ++                name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
  1008. ++                if (name == 0)
  1009. ++                  name = tname;
  1010. ++                else
  1011. ++                  free (tname);
  1012. ++              }
  1013. ++           else
  1014. ++              name = tname;
  1015. ++          }
  1016. ++        else
  1017. ++          {
  1018. ++            if (current_user.shell == 0)
  1019. ++              get_current_user_info ();
  1020. ++            name = savestring (current_user.shell);
  1021. ++          }
  1022. ++      }
  1023. ++      else
  1024. ++      {
  1025. ++        name = full_pathname (tname);
  1026. ++        free (tname);
  1027. ++      }
  1028. ++    }
  1029. ++
  1030. ++  return (name);
  1031. ++}
  1032. ++
  1033. ++void
  1034. ++adjust_shell_level (change)
  1035. ++     int change;
  1036. ++{
  1037. ++  char new_level[5], *old_SHLVL;
  1038. ++  intmax_t old_level;
  1039. ++  SHELL_VAR *temp_var;
  1040. ++
  1041. ++  old_SHLVL = get_string_value ("SHLVL");
  1042. ++  if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
  1043. ++    old_level = 0;
  1044. ++
  1045. ++  shell_level = old_level + change;
  1046. ++  if (shell_level < 0)
  1047. ++    shell_level = 0;
  1048. ++  else if (shell_level > 1000)
  1049. ++    {
  1050. ++      internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
  1051. ++      shell_level = 1;
  1052. ++    }
  1053. ++
  1054. ++  /* We don't need the full generality of itos here. */
  1055. ++  if (shell_level < 10)
  1056. ++    {
  1057. ++      new_level[0] = shell_level + '0';
  1058. ++      new_level[1] = '\0';
  1059. ++    }
  1060. ++  else if (shell_level < 100)
  1061. ++    {
  1062. ++      new_level[0] = (shell_level / 10) + '0';
  1063. ++      new_level[1] = (shell_level % 10) + '0';
  1064. ++      new_level[2] = '\0';
  1065. ++    }
  1066. ++  else if (shell_level < 1000)
  1067. ++    {
  1068. ++      new_level[0] = (shell_level / 100) + '0';
  1069. ++      old_level = shell_level % 100;
  1070. ++      new_level[1] = (old_level / 10) + '0';
  1071. ++      new_level[2] = (old_level % 10) + '0';
  1072. ++      new_level[3] = '\0';
  1073. ++    }
  1074. ++
  1075. ++  temp_var = bind_variable ("SHLVL", new_level, 0);
  1076. ++  set_auto_export (temp_var);
  1077. ++}
  1078. ++
  1079. ++static void
  1080. ++initialize_shell_level ()
  1081. ++{
  1082. ++  adjust_shell_level (1);
  1083. ++}
  1084. ++
  1085. ++/* If we got PWD from the environment, update our idea of the current
  1086. ++   working directory.  In any case, make sure that PWD exists before
  1087. ++   checking it.  It is possible for getcwd () to fail on shell startup,
  1088. ++   and in that case, PWD would be undefined.  If this is an interactive
  1089. ++   login shell, see if $HOME is the current working directory, and if
  1090. ++   that's not the same string as $PWD, set PWD=$HOME. */
  1091. ++
  1092. ++void
  1093. ++set_pwd ()
  1094. ++{
  1095. ++  SHELL_VAR *temp_var, *home_var;
  1096. ++  char *temp_string, *home_string;
  1097. ++
  1098. ++  home_var = find_variable ("HOME");
  1099. ++  home_string = home_var ? value_cell (home_var) : (char *)NULL;
  1100. ++
  1101. ++  temp_var = find_variable ("PWD");
  1102. ++  if (temp_var && imported_p (temp_var) &&
  1103. ++      (temp_string = value_cell (temp_var)) &&
  1104. ++      same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
  1105. ++    set_working_directory (temp_string);
  1106. ++  else if (home_string && interactive_shell && login_shell &&
  1107. ++         same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
  1108. ++    {
  1109. ++      set_working_directory (home_string);
  1110. ++      temp_var = bind_variable ("PWD", home_string, 0);
  1111. ++      set_auto_export (temp_var);
  1112. ++    }
  1113. ++  else
  1114. ++    {
  1115. ++      temp_string = get_working_directory ("shell-init");
  1116. ++      if (temp_string)
  1117. ++      {
  1118. ++        temp_var = bind_variable ("PWD", temp_string, 0);
  1119. ++        set_auto_export (temp_var);
  1120. ++        free (temp_string);
  1121. ++      }
  1122. ++    }
  1123. ++
  1124. ++  /* According to the Single Unix Specification, v2, $OLDPWD is an
  1125. ++     `environment variable' and therefore should be auto-exported.
  1126. ++     Make a dummy invisible variable for OLDPWD, and mark it as exported. */
  1127. ++  temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
  1128. ++  VSETATTR (temp_var, (att_exported | att_invisible));
  1129. ++}
  1130. ++
  1131. ++/* Make a variable $PPID, which holds the pid of the shell's parent.  */
  1132. ++void
  1133. ++set_ppid ()
  1134. ++{
  1135. ++  char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
  1136. ++  SHELL_VAR *temp_var;
  1137. ++
  1138. ++  name = inttostr (getppid (), namebuf, sizeof(namebuf));
  1139. ++  temp_var = find_variable ("PPID");
  1140. ++  if (temp_var)
  1141. ++    VUNSETATTR (temp_var, (att_readonly | att_exported));
  1142. ++  temp_var = bind_variable ("PPID", name, 0);
  1143. ++  VSETATTR (temp_var, (att_readonly | att_integer));
  1144. ++}
  1145. ++
  1146. ++static void
  1147. ++uidset ()
  1148. ++{
  1149. ++  char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
  1150. ++  register SHELL_VAR *v;
  1151. ++
  1152. ++  b = inttostr (current_user.uid, buff, sizeof (buff));
  1153. ++  v = find_variable ("UID");
  1154. ++  if (v == 0)
  1155. ++    {
  1156. ++      v = bind_variable ("UID", b, 0);
  1157. ++      VSETATTR (v, (att_readonly | att_integer));
  1158. ++    }
  1159. ++
  1160. ++  if (current_user.euid != current_user.uid)
  1161. ++    b = inttostr (current_user.euid, buff, sizeof (buff));
  1162. ++
  1163. ++  v = find_variable ("EUID");
  1164. ++  if (v == 0)
  1165. ++    {
  1166. ++      v = bind_variable ("EUID", b, 0);
  1167. ++      VSETATTR (v, (att_readonly | att_integer));
  1168. ++    }
  1169. ++}
  1170. ++
  1171. ++#if defined (ARRAY_VARS)
  1172. ++static void
  1173. ++make_vers_array ()
  1174. ++{
  1175. ++  SHELL_VAR *vv;
  1176. ++  ARRAY *av;
  1177. ++  char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
  1178. ++
  1179. ++  unbind_variable ("BASH_VERSINFO");
  1180. ++
  1181. ++  vv = make_new_array_variable ("BASH_VERSINFO");
  1182. ++  av = array_cell (vv);
  1183. ++  strcpy (d, dist_version);
  1184. ++  s = strchr (d, '.');
  1185. ++  if (s)
  1186. ++    *s++ = '\0';
  1187. ++  array_insert (av, 0, d);
  1188. ++  array_insert (av, 1, s);
  1189. ++  s = inttostr (patch_level, b, sizeof (b));
  1190. ++  array_insert (av, 2, s);
  1191. ++  s = inttostr (build_version, b, sizeof (b));
  1192. ++  array_insert (av, 3, s);
  1193. ++  array_insert (av, 4, release_status);
  1194. ++  array_insert (av, 5, MACHTYPE);
  1195. ++
  1196. ++  VSETATTR (vv, att_readonly);
  1197. ++}
  1198. ++#endif /* ARRAY_VARS */
  1199. ++
  1200. ++/* Set the environment variables $LINES and $COLUMNS in response to
  1201. ++   a window size change. */
  1202. ++void
  1203. ++sh_set_lines_and_columns (lines, cols)
  1204. ++     int lines, cols;
  1205. ++{
  1206. ++  char val[INT_STRLEN_BOUND(int) + 1], *v;
  1207. ++
  1208. ++#if defined (READLINE)
  1209. ++  /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
  1210. ++  if (winsize_assignment)
  1211. ++    return;
  1212. ++#endif
  1213. ++
  1214. ++  v = inttostr (lines, val, sizeof (val));
  1215. ++  bind_variable ("LINES", v, 0);
  1216. ++
  1217. ++  v = inttostr (cols, val, sizeof (val));
  1218. ++  bind_variable ("COLUMNS", v, 0);
  1219. ++}
  1220. ++
  1221. ++/* **************************************************************** */
  1222. ++/*                                                                */
  1223. ++/*               Printing variables and values                    */
  1224. ++/*                                                                */
  1225. ++/* **************************************************************** */
  1226. ++
  1227. ++/* Print LIST (a list of shell variables) to stdout in such a way that
  1228. ++   they can be read back in. */
  1229. ++void
  1230. ++print_var_list (list)
  1231. ++     register SHELL_VAR **list;
  1232. ++{
  1233. ++  register int i;
  1234. ++  register SHELL_VAR *var;
  1235. ++
  1236. ++  for (i = 0; list && (var = list[i]); i++)
  1237. ++    if (invisible_p (var) == 0)
  1238. ++      print_assignment (var);
  1239. ++}
  1240. ++
  1241. ++/* Print LIST (a list of shell functions) to stdout in such a way that
  1242. ++   they can be read back in. */
  1243. ++void
  1244. ++print_func_list (list)
  1245. ++     register SHELL_VAR **list;
  1246. ++{
  1247. ++  register int i;
  1248. ++  register SHELL_VAR *var;
  1249. ++
  1250. ++  for (i = 0; list && (var = list[i]); i++)
  1251. ++    {
  1252. ++      printf ("%s ", var->name);
  1253. ++      print_var_function (var);
  1254. ++      printf ("\n");
  1255. ++    }
  1256. ++}
  1257. ++      
  1258. ++/* Print the value of a single SHELL_VAR.  No newline is
  1259. ++   output, but the variable is printed in such a way that
  1260. ++   it can be read back in. */
  1261. ++void
  1262. ++print_assignment (var)
  1263. ++     SHELL_VAR *var;
  1264. ++{
  1265. ++  if (var_isset (var) == 0)
  1266. ++    return;
  1267. ++
  1268. ++  if (function_p (var))
  1269. ++    {
  1270. ++      printf ("%s", var->name);
  1271. ++      print_var_function (var);
  1272. ++      printf ("\n");
  1273. ++    }
  1274. ++#if defined (ARRAY_VARS)
  1275. ++  else if (array_p (var))
  1276. ++    print_array_assignment (var, 0);
  1277. ++  else if (assoc_p (var))
  1278. ++    print_assoc_assignment (var, 0);
  1279. ++#endif /* ARRAY_VARS */
  1280. ++  else
  1281. ++    {
  1282. ++      printf ("%s=", var->name);
  1283. ++      print_var_value (var, 1);
  1284. ++      printf ("\n");
  1285. ++    }
  1286. ++}
  1287. ++
  1288. ++/* Print the value cell of VAR, a shell variable.  Do not print
  1289. ++   the name, nor leading/trailing newline.  If QUOTE is non-zero,
  1290. ++   and the value contains shell metacharacters, quote the value
  1291. ++   in such a way that it can be read back in. */
  1292. ++void
  1293. ++print_var_value (var, quote)
  1294. ++     SHELL_VAR *var;
  1295. ++     int quote;
  1296. ++{
  1297. ++  char *t;
  1298. ++
  1299. ++  if (var_isset (var) == 0)
  1300. ++    return;
  1301. ++
  1302. ++  if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
  1303. ++    {
  1304. ++      t = ansic_quote (value_cell (var), 0, (int *)0);
  1305. ++      printf ("%s", t);
  1306. ++      free (t);
  1307. ++    }
  1308. ++  else if (quote && sh_contains_shell_metas (value_cell (var)))
  1309. ++    {
  1310. ++      t = sh_single_quote (value_cell (var));
  1311. ++      printf ("%s", t);
  1312. ++      free (t);
  1313. ++    }
  1314. ++  else
  1315. ++    printf ("%s", value_cell (var));
  1316. ++}
  1317. ++
  1318. ++/* Print the function cell of VAR, a shell variable.  Do not
  1319. ++   print the name, nor leading/trailing newline. */
  1320. ++void
  1321. ++print_var_function (var)
  1322. ++     SHELL_VAR *var;
  1323. ++{
  1324. ++  char *x;
  1325. ++
  1326. ++  if (function_p (var) && var_isset (var))
  1327. ++    {
  1328. ++      x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
  1329. ++      printf ("%s", x);
  1330. ++    }
  1331. ++}
  1332. ++
  1333. ++/* **************************************************************** */
  1334. ++/*                                                                */
  1335. ++/*                    Dynamic Variables                           */
  1336. ++/*                                                                */
  1337. ++/* **************************************************************** */
  1338. ++
  1339. ++/* DYNAMIC VARIABLES
  1340. ++
  1341. ++   These are variables whose values are generated anew each time they are
  1342. ++   referenced.  These are implemented using a pair of function pointers
  1343. ++   in the struct variable: assign_func, which is called from bind_variable
  1344. ++   and, if arrays are compiled into the shell, some of the functions in
  1345. ++   arrayfunc.c, and dynamic_value, which is called from find_variable.
  1346. ++
  1347. ++   assign_func is called from bind_variable_internal, if
  1348. ++   bind_variable_internal discovers that the variable being assigned to
  1349. ++   has such a function.  The function is called as
  1350. ++      SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
  1351. ++   and the (SHELL_VAR *)temp is returned as the value of bind_variable.  It
  1352. ++   is usually ENTRY (self).  IND is an index for an array variable, and
  1353. ++   unused otherwise.
  1354. ++
  1355. ++   dynamic_value is called from find_variable_internal to return a `new'
  1356. ++   value for the specified dynamic varible.  If this function is NULL,
  1357. ++   the variable is treated as a `normal' shell variable.  If it is not,
  1358. ++   however, then this function is called like this:
  1359. ++      tempvar = (*(var->dynamic_value)) (var);
  1360. ++
  1361. ++   Sometimes `tempvar' will replace the value of `var'.  Other times, the
  1362. ++   shell will simply use the string value.  Pretty object-oriented, huh?
  1363. ++
  1364. ++   Be warned, though: if you `unset' a special variable, it loses its
  1365. ++   special meaning, even if you subsequently set it.
  1366. ++
  1367. ++   The special assignment code would probably have been better put in
  1368. ++   subst.c: do_assignment_internal, in the same style as
  1369. ++   stupidly_hack_special_variables, but I wanted the changes as
  1370. ++   localized as possible.  */
  1371. ++
  1372. ++#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
  1373. ++  do \
  1374. ++    { \
  1375. ++      v = bind_variable (var, (val), 0); \
  1376. ++      v->dynamic_value = gfunc; \
  1377. ++      v->assign_func = afunc; \
  1378. ++    } \
  1379. ++  while (0)
  1380. ++
  1381. ++#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
  1382. ++  do \
  1383. ++    { \
  1384. ++      v = make_new_array_variable (var); \
  1385. ++      v->dynamic_value = gfunc; \
  1386. ++      v->assign_func = afunc; \
  1387. ++    } \
  1388. ++  while (0)
  1389. ++
  1390. ++#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
  1391. ++  do \
  1392. ++    { \
  1393. ++      v = make_new_assoc_variable (var); \
  1394. ++      v->dynamic_value = gfunc; \
  1395. ++      v->assign_func = afunc; \
  1396. ++    } \
  1397. ++  while (0)
  1398. ++
  1399. ++static SHELL_VAR *
  1400. ++null_assign (self, value, unused, key)
  1401. ++     SHELL_VAR *self;
  1402. ++     char *value;
  1403. ++     arrayind_t unused;
  1404. ++     char *key;
  1405. ++{
  1406. ++  return (self);
  1407. ++}
  1408. ++
  1409. ++#if defined (ARRAY_VARS)
  1410. ++static SHELL_VAR *
  1411. ++null_array_assign (self, value, ind, key)
  1412. ++     SHELL_VAR *self;
  1413. ++     char *value;
  1414. ++     arrayind_t ind;
  1415. ++     char *key;
  1416. ++{
  1417. ++  return (self);
  1418. ++}
  1419. ++#endif
  1420. ++
  1421. ++/* Degenerate `dynamic_value' function; just returns what's passed without
  1422. ++   manipulation. */
  1423. ++static SHELL_VAR *
  1424. ++get_self (self)
  1425. ++     SHELL_VAR *self;
  1426. ++{
  1427. ++  return (self);
  1428. ++}
  1429. ++
  1430. ++#if defined (ARRAY_VARS)
  1431. ++/* A generic dynamic array variable initializer.  Initialize array variable
  1432. ++   NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
  1433. ++static SHELL_VAR *
  1434. ++init_dynamic_array_var (name, getfunc, setfunc, attrs)
  1435. ++     char *name;
  1436. ++     sh_var_value_func_t *getfunc;
  1437. ++     sh_var_assign_func_t *setfunc;
  1438. ++     int attrs;
  1439. ++{
  1440. ++  SHELL_VAR *v;
  1441. ++
  1442. ++  v = find_variable (name);
  1443. ++  if (v)
  1444. ++    return (v);
  1445. ++  INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
  1446. ++  if (attrs)
  1447. ++    VSETATTR (v, attrs);
  1448. ++  return v;
  1449. ++}
  1450. ++
  1451. ++static SHELL_VAR *
  1452. ++init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
  1453. ++     char *name;
  1454. ++     sh_var_value_func_t *getfunc;
  1455. ++     sh_var_assign_func_t *setfunc;
  1456. ++     int attrs;
  1457. ++{
  1458. ++  SHELL_VAR *v;
  1459. ++
  1460. ++  v = find_variable (name);
  1461. ++  if (v)
  1462. ++    return (v);
  1463. ++  INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
  1464. ++  if (attrs)
  1465. ++    VSETATTR (v, attrs);
  1466. ++  return v;
  1467. ++}
  1468. ++#endif
  1469. ++
  1470. ++/* The value of $SECONDS.  This is the number of seconds since shell
  1471. ++   invocation, or, the number of seconds since the last assignment + the
  1472. ++   value of the last assignment. */
  1473. ++static intmax_t seconds_value_assigned;
  1474. ++
  1475. ++static SHELL_VAR *
  1476. ++assign_seconds (self, value, unused, key)
  1477. ++     SHELL_VAR *self;
  1478. ++     char *value;
  1479. ++     arrayind_t unused;
  1480. ++     char *key;
  1481. ++{
  1482. ++  if (legal_number (value, &seconds_value_assigned) == 0)
  1483. ++    seconds_value_assigned = 0;
  1484. ++  shell_start_time = NOW;
  1485. ++  return (self);
  1486. ++}
  1487. ++
  1488. ++static SHELL_VAR *
  1489. ++get_seconds (var)
  1490. ++     SHELL_VAR *var;
  1491. ++{
  1492. ++  time_t time_since_start;
  1493. ++  char *p;
  1494. ++
  1495. ++  time_since_start = NOW - shell_start_time;
  1496. ++  p = itos(seconds_value_assigned + time_since_start);
  1497. ++
  1498. ++  FREE (value_cell (var));
  1499. ++
  1500. ++  VSETATTR (var, att_integer);
  1501. ++  var_setvalue (var, p);
  1502. ++  return (var);
  1503. ++}
  1504. ++
  1505. ++static SHELL_VAR *
  1506. ++init_seconds_var ()
  1507. ++{
  1508. ++  SHELL_VAR *v;
  1509. ++
  1510. ++  v = find_variable ("SECONDS");
  1511. ++  if (v)
  1512. ++    {
  1513. ++      if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
  1514. ++      seconds_value_assigned = 0;
  1515. ++    }
  1516. ++  INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
  1517. ++  return v;      
  1518. ++}
  1519. ++    
  1520. ++/* The random number seed.  You can change this by setting RANDOM. */
  1521. ++static unsigned long rseed = 1;
  1522. ++static int last_random_value;
  1523. ++static int seeded_subshell = 0;
  1524. ++
  1525. ++/* A linear congruential random number generator based on the example
  1526. ++   one in the ANSI C standard.  This one isn't very good, but a more
  1527. ++   complicated one is overkill. */
  1528. ++
  1529. ++/* Returns a pseudo-random number between 0 and 32767. */
  1530. ++static int
  1531. ++brand ()
  1532. ++{
  1533. ++  /* From "Random number generators: good ones are hard to find",
  1534. ++     Park and Miller, Communications of the ACM, vol. 31, no. 10,
  1535. ++     October 1988, p. 1195. filtered through FreeBSD */
  1536. ++  long h, l;
  1537. ++
  1538. ++  /* Can't seed with 0. */
  1539. ++  if (rseed == 0)
  1540. ++    rseed = 123459876;
  1541. ++  h = rseed / 127773;
  1542. ++  l = rseed % 127773;
  1543. ++  rseed = 16807 * l - 2836 * h;
  1544. ++#if 0
  1545. ++  if (rseed < 0)
  1546. ++    rseed += 0x7fffffff;
  1547. ++#endif
  1548. ++  return ((unsigned int)(rseed & 32767));     /* was % 32768 */
  1549. ++}
  1550. ++
  1551. ++/* Set the random number generator seed to SEED. */
  1552. ++static void
  1553. ++sbrand (seed)
  1554. ++     unsigned long seed;
  1555. ++{
  1556. ++  rseed = seed;
  1557. ++  last_random_value = 0;
  1558. ++}
  1559. ++
  1560. ++static void
  1561. ++seedrand ()
  1562. ++{
  1563. ++  struct timeval tv;
  1564. ++
  1565. ++  gettimeofday (&tv, NULL);
  1566. ++  sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
  1567. ++}
  1568. ++
  1569. ++static SHELL_VAR *
  1570. ++assign_random (self, value, unused, key)
  1571. ++     SHELL_VAR *self;
  1572. ++     char *value;
  1573. ++     arrayind_t unused;
  1574. ++     char *key;
  1575. ++{
  1576. ++  sbrand (strtoul (value, (char **)NULL, 10));
  1577. ++  if (subshell_environment)
  1578. ++    seeded_subshell = getpid ();
  1579. ++  return (self);
  1580. ++}
  1581. ++
  1582. ++int
  1583. ++get_random_number ()
  1584. ++{
  1585. ++  int rv, pid;
  1586. ++
  1587. ++  /* Reset for command and process substitution. */
  1588. ++  pid = getpid ();
  1589. ++  if (subshell_environment && seeded_subshell != pid)
  1590. ++    {
  1591. ++      seedrand ();
  1592. ++      seeded_subshell = pid;
  1593. ++    }
  1594. ++
  1595. ++  do
  1596. ++    rv = brand ();
  1597. ++  while (rv == last_random_value);
  1598. ++  return rv;
  1599. ++}
  1600. ++
  1601. ++static SHELL_VAR *
  1602. ++get_random (var)
  1603. ++     SHELL_VAR *var;
  1604. ++{
  1605. ++  int rv;
  1606. ++  char *p;
  1607. ++
  1608. ++  rv = get_random_number ();
  1609. ++  last_random_value = rv;
  1610. ++  p = itos (rv);
  1611. ++
  1612. ++  FREE (value_cell (var));
  1613. ++
  1614. ++  VSETATTR (var, att_integer);
  1615. ++  var_setvalue (var, p);
  1616. ++  return (var);
  1617. ++}
  1618. ++
  1619. ++static SHELL_VAR *
  1620. ++assign_lineno (var, value, unused, key)
  1621. ++     SHELL_VAR *var;
  1622. ++     char *value;
  1623. ++     arrayind_t unused;
  1624. ++     char *key;
  1625. ++{
  1626. ++  intmax_t new_value;
  1627. ++
  1628. ++  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
  1629. ++    new_value = 0;
  1630. ++  line_number = line_number_base = new_value;
  1631. ++  return var;
  1632. ++}
  1633. ++
  1634. ++/* Function which returns the current line number. */
  1635. ++static SHELL_VAR *
  1636. ++get_lineno (var)
  1637. ++     SHELL_VAR *var;
  1638. ++{
  1639. ++  char *p;
  1640. ++  int ln;
  1641. ++
  1642. ++  ln = executing_line_number ();
  1643. ++  p = itos (ln);
  1644. ++  FREE (value_cell (var));
  1645. ++  var_setvalue (var, p);
  1646. ++  return (var);
  1647. ++}
  1648. ++
  1649. ++static SHELL_VAR *
  1650. ++assign_subshell (var, value, unused, key)
  1651. ++     SHELL_VAR *var;
  1652. ++     char *value;
  1653. ++     arrayind_t unused;
  1654. ++     char *key;
  1655. ++{
  1656. ++  intmax_t new_value;
  1657. ++
  1658. ++  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
  1659. ++    new_value = 0;
  1660. ++  subshell_level = new_value;
  1661. ++  return var;
  1662. ++}
  1663. ++
  1664. ++static SHELL_VAR *
  1665. ++get_subshell (var)
  1666. ++     SHELL_VAR *var;
  1667. ++{
  1668. ++  char *p;
  1669. ++
  1670. ++  p = itos (subshell_level);
  1671. ++  FREE (value_cell (var));
  1672. ++  var_setvalue (var, p);
  1673. ++  return (var);
  1674. ++}
  1675. ++
  1676. ++static SHELL_VAR *
  1677. ++get_bashpid (var)
  1678. ++     SHELL_VAR *var;
  1679. ++{
  1680. ++  int pid;
  1681. ++  char *p;
  1682. ++
  1683. ++  pid = getpid ();
  1684. ++  p = itos (pid);
  1685. ++
  1686. ++  FREE (value_cell (var));
  1687. ++  VSETATTR (var, att_integer|att_readonly);
  1688. ++  var_setvalue (var, p);
  1689. ++  return (var);
  1690. ++}
  1691. ++
  1692. ++static SHELL_VAR *
  1693. ++get_bash_command (var)
  1694. ++     SHELL_VAR *var;
  1695. ++{
  1696. ++  char *p;
  1697. ++
  1698. ++  if (the_printed_command_except_trap)
  1699. ++    p = savestring (the_printed_command_except_trap);
  1700. ++  else
  1701. ++    {
  1702. ++      p = (char *)xmalloc (1);
  1703. ++      p[0] = '\0';
  1704. ++    }
  1705. ++  FREE (value_cell (var));
  1706. ++  var_setvalue (var, p);
  1707. ++  return (var);
  1708. ++}
  1709. ++
  1710. ++#if defined (HISTORY)
  1711. ++static SHELL_VAR *
  1712. ++get_histcmd (var)
  1713. ++     SHELL_VAR *var;
  1714. ++{
  1715. ++  char *p;
  1716. ++
  1717. ++  p = itos (history_number ());
  1718. ++  FREE (value_cell (var));
  1719. ++  var_setvalue (var, p);
  1720. ++  return (var);
  1721. ++}
  1722. ++#endif
  1723. ++
  1724. ++#if defined (READLINE)
  1725. ++/* When this function returns, VAR->value points to malloced memory. */
  1726. ++static SHELL_VAR *
  1727. ++get_comp_wordbreaks (var)
  1728. ++     SHELL_VAR *var;
  1729. ++{
  1730. ++  /* If we don't have anything yet, assign a default value. */
  1731. ++  if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
  1732. ++    enable_hostname_completion (perform_hostname_completion);
  1733. ++
  1734. ++  FREE (value_cell (var));
  1735. ++  var_setvalue (var, savestring (rl_completer_word_break_characters));
  1736. ++
  1737. ++  return (var);
  1738. ++}
  1739. ++
  1740. ++/* When this function returns, rl_completer_word_break_characters points to
  1741. ++   malloced memory. */
  1742. ++static SHELL_VAR *
  1743. ++assign_comp_wordbreaks (self, value, unused, key)
  1744. ++     SHELL_VAR *self;
  1745. ++     char *value;
  1746. ++     arrayind_t unused;
  1747. ++     char *key;
  1748. ++{
  1749. ++  if (rl_completer_word_break_characters &&
  1750. ++      rl_completer_word_break_characters != rl_basic_word_break_characters)
  1751. ++    free (rl_completer_word_break_characters);
  1752. ++
  1753. ++  rl_completer_word_break_characters = savestring (value);
  1754. ++  return self;
  1755. ++}
  1756. ++#endif /* READLINE */
  1757. ++
  1758. ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  1759. ++static SHELL_VAR *
  1760. ++assign_dirstack (self, value, ind, key)
  1761. ++     SHELL_VAR *self;
  1762. ++     char *value;
  1763. ++     arrayind_t ind;
  1764. ++     char *key;
  1765. ++{
  1766. ++  set_dirstack_element (ind, 1, value);
  1767. ++  return self;
  1768. ++}
  1769. ++
  1770. ++static SHELL_VAR *
  1771. ++get_dirstack (self)
  1772. ++     SHELL_VAR *self;
  1773. ++{
  1774. ++  ARRAY *a;
  1775. ++  WORD_LIST *l;
  1776. ++
  1777. ++  l = get_directory_stack (0);
  1778. ++  a = array_from_word_list (l);
  1779. ++  array_dispose (array_cell (self));
  1780. ++  dispose_words (l);
  1781. ++  var_setarray (self, a);
  1782. ++  return self;
  1783. ++}
  1784. ++#endif /* PUSHD AND POPD && ARRAY_VARS */
  1785. ++
  1786. ++#if defined (ARRAY_VARS)
  1787. ++/* We don't want to initialize the group set with a call to getgroups()
  1788. ++   unless we're asked to, but we only want to do it once. */
  1789. ++static SHELL_VAR *
  1790. ++get_groupset (self)
  1791. ++     SHELL_VAR *self;
  1792. ++{
  1793. ++  register int i;
  1794. ++  int ng;
  1795. ++  ARRAY *a;
  1796. ++  static char **group_set = (char **)NULL;
  1797. ++
  1798. ++  if (group_set == 0)
  1799. ++    {
  1800. ++      group_set = get_group_list (&ng);
  1801. ++      a = array_cell (self);
  1802. ++      for (i = 0; i < ng; i++)
  1803. ++      array_insert (a, i, group_set[i]);
  1804. ++    }
  1805. ++  return (self);
  1806. ++}
  1807. ++
  1808. ++static SHELL_VAR *
  1809. ++build_hashcmd (self)
  1810. ++     SHELL_VAR *self;
  1811. ++{
  1812. ++  HASH_TABLE *h;
  1813. ++  int i;
  1814. ++  char *k, *v;
  1815. ++  BUCKET_CONTENTS *item;
  1816. ++
  1817. ++  h = assoc_cell (self);
  1818. ++  if (h)
  1819. ++    assoc_dispose (h);
  1820. ++
  1821. ++  if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
  1822. ++    {
  1823. ++      var_setvalue (self, (char *)NULL);
  1824. ++      return self;
  1825. ++    }
  1826. ++
  1827. ++  h = assoc_create (hashed_filenames->nbuckets);
  1828. ++  for (i = 0; i < hashed_filenames->nbuckets; i++)
  1829. ++    {
  1830. ++      for (item = hash_items (i, hashed_filenames); item; item = item->next)
  1831. ++      {
  1832. ++        k = savestring (item->key);
  1833. ++        v = pathdata(item)->path;
  1834. ++        assoc_insert (h, k, v);
  1835. ++      }
  1836. ++    }
  1837. ++
  1838. ++  var_setvalue (self, (char *)h);
  1839. ++  return self;
  1840. ++}
  1841. ++
  1842. ++static SHELL_VAR *
  1843. ++get_hashcmd (self)
  1844. ++     SHELL_VAR *self;
  1845. ++{
  1846. ++  build_hashcmd (self);
  1847. ++  return (self);
  1848. ++}
  1849. ++
  1850. ++static SHELL_VAR *
  1851. ++assign_hashcmd (self, value, ind, key)
  1852. ++     SHELL_VAR *self;
  1853. ++     char *value;
  1854. ++     arrayind_t ind;
  1855. ++     char *key;
  1856. ++{
  1857. ++  phash_insert (key, value, 0, 0);
  1858. ++  return (build_hashcmd (self));
  1859. ++}
  1860. ++
  1861. ++#if defined (ALIAS)
  1862. ++static SHELL_VAR *
  1863. ++build_aliasvar (self)
  1864. ++     SHELL_VAR *self;
  1865. ++{
  1866. ++  HASH_TABLE *h;
  1867. ++  int i;
  1868. ++  char *k, *v;
  1869. ++  BUCKET_CONTENTS *item;
  1870. ++
  1871. ++  h = assoc_cell (self);
  1872. ++  if (h)
  1873. ++    assoc_dispose (h);
  1874. ++
  1875. ++  if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
  1876. ++    {
  1877. ++      var_setvalue (self, (char *)NULL);
  1878. ++      return self;
  1879. ++    }
  1880. ++
  1881. ++  h = assoc_create (aliases->nbuckets);
  1882. ++  for (i = 0; i < aliases->nbuckets; i++)
  1883. ++    {
  1884. ++      for (item = hash_items (i, aliases); item; item = item->next)
  1885. ++      {
  1886. ++        k = savestring (item->key);
  1887. ++        v = ((alias_t *)(item->data))->value;
  1888. ++        assoc_insert (h, k, v);
  1889. ++      }
  1890. ++    }
  1891. ++
  1892. ++  var_setvalue (self, (char *)h);
  1893. ++  return self;
  1894. ++}
  1895. ++
  1896. ++static SHELL_VAR *
  1897. ++get_aliasvar (self)
  1898. ++     SHELL_VAR *self;
  1899. ++{
  1900. ++  build_aliasvar (self);
  1901. ++  return (self);
  1902. ++}
  1903. ++
  1904. ++static SHELL_VAR *
  1905. ++assign_aliasvar (self, value, ind, key)
  1906. ++     SHELL_VAR *self;
  1907. ++     char *value;
  1908. ++     arrayind_t ind;
  1909. ++     char *key;
  1910. ++{
  1911. ++  add_alias (key, value);
  1912. ++  return (build_aliasvar (self));
  1913. ++}
  1914. ++#endif /* ALIAS */
  1915. ++
  1916. ++#endif /* ARRAY_VARS */
  1917. ++
  1918. ++/* If ARRAY_VARS is not defined, this just returns the name of any
  1919. ++   currently-executing function.  If we have arrays, it's a call stack. */
  1920. ++static SHELL_VAR *
  1921. ++get_funcname (self)
  1922. ++     SHELL_VAR *self;
  1923. ++{
  1924. ++#if ! defined (ARRAY_VARS)
  1925. ++  char *t;
  1926. ++  if (variable_context && this_shell_function)
  1927. ++    {
  1928. ++      FREE (value_cell (self));
  1929. ++      t = savestring (this_shell_function->name);
  1930. ++      var_setvalue (self, t);
  1931. ++    }
  1932. ++#endif
  1933. ++  return (self);
  1934. ++}
  1935. ++
  1936. ++void
  1937. ++make_funcname_visible (on_or_off)
  1938. ++     int on_or_off;
  1939. ++{
  1940. ++  SHELL_VAR *v;
  1941. ++
  1942. ++  v = find_variable ("FUNCNAME");
  1943. ++  if (v == 0 || v->dynamic_value == 0)
  1944. ++    return;
  1945. ++
  1946. ++  if (on_or_off)
  1947. ++    VUNSETATTR (v, att_invisible);
  1948. ++  else
  1949. ++    VSETATTR (v, att_invisible);
  1950. ++}
  1951. ++
  1952. ++static SHELL_VAR *
  1953. ++init_funcname_var ()
  1954. ++{
  1955. ++  SHELL_VAR *v;
  1956. ++
  1957. ++  v = find_variable ("FUNCNAME");
  1958. ++  if (v)
  1959. ++    return v;
  1960. ++#if defined (ARRAY_VARS)
  1961. ++  INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
  1962. ++#else
  1963. ++  INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
  1964. ++#endif
  1965. ++  VSETATTR (v, att_invisible|att_noassign);
  1966. ++  return v;
  1967. ++}
  1968. ++
  1969. ++static void
  1970. ++initialize_dynamic_variables ()
  1971. ++{
  1972. ++  SHELL_VAR *v;
  1973. ++
  1974. ++  v = init_seconds_var ();
  1975. ++
  1976. ++  INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
  1977. ++  INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
  1978. ++
  1979. ++  INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
  1980. ++  VSETATTR (v, att_integer);
  1981. ++  INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
  1982. ++  VSETATTR (v, att_integer);
  1983. ++
  1984. ++  INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
  1985. ++  VSETATTR (v, att_integer|att_readonly);
  1986. ++
  1987. ++#if defined (HISTORY)
  1988. ++  INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
  1989. ++  VSETATTR (v, att_integer);
  1990. ++#endif
  1991. ++
  1992. ++#if defined (READLINE)
  1993. ++  INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
  1994. ++#endif
  1995. ++
  1996. ++#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  1997. ++  v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
  1998. ++#endif /* PUSHD_AND_POPD && ARRAY_VARS */
  1999. ++
  2000. ++#if defined (ARRAY_VARS)
  2001. ++  v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
  2002. ++
  2003. ++#  if defined (DEBUGGER)
  2004. ++  v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
  2005. ++  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
  2006. ++#  endif /* DEBUGGER */
  2007. ++  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
  2008. ++  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
  2009. ++
  2010. ++  v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
  2011. ++#  if defined (ALIAS)
  2012. ++  v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
  2013. ++#  endif
  2014. ++#endif
  2015. ++
  2016. ++  v = init_funcname_var ();
  2017. ++}
  2018. ++
  2019. ++/* **************************************************************** */
  2020. ++/*                                                                */
  2021. ++/*            Retrieving variables and values                     */
  2022. ++/*                                                                */
  2023. ++/* **************************************************************** */
  2024. ++
  2025. ++/* How to get a pointer to the shell variable or function named NAME.
  2026. ++   HASHED_VARS is a pointer to the hash table containing the list
  2027. ++   of interest (either variables or functions). */
  2028. ++
  2029. ++static SHELL_VAR *
  2030. ++hash_lookup (name, hashed_vars)
  2031. ++     const char *name;
  2032. ++     HASH_TABLE *hashed_vars;
  2033. ++{
  2034. ++  BUCKET_CONTENTS *bucket;
  2035. ++
  2036. ++  bucket = hash_search (name, hashed_vars, 0);
  2037. ++  /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
  2038. ++     table. */
  2039. ++  if (bucket)
  2040. ++    last_table_searched = hashed_vars;
  2041. ++  return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
  2042. ++}
  2043. ++
  2044. ++SHELL_VAR *
  2045. ++var_lookup (name, vcontext)
  2046. ++     const char *name;
  2047. ++     VAR_CONTEXT *vcontext;
  2048. ++{
  2049. ++  VAR_CONTEXT *vc;
  2050. ++  SHELL_VAR *v;
  2051. ++
  2052. ++  v = (SHELL_VAR *)NULL;
  2053. ++  for (vc = vcontext; vc; vc = vc->down)
  2054. ++    if (v = hash_lookup (name, vc->table))
  2055. ++      break;
  2056. ++
  2057. ++  return v;
  2058. ++}
  2059. ++
  2060. ++/* Look up the variable entry named NAME.  If SEARCH_TEMPENV is non-zero,
  2061. ++   then also search the temporarily built list of exported variables.
  2062. ++   The lookup order is:
  2063. ++      temporary_env
  2064. ++      shell_variables list
  2065. ++*/
  2066. ++
  2067. ++SHELL_VAR *
  2068. ++find_variable_internal (name, force_tempenv)
  2069. ++     const char *name;
  2070. ++     int force_tempenv;
  2071. ++{
  2072. ++  SHELL_VAR *var;
  2073. ++  int search_tempenv;
  2074. ++  VAR_CONTEXT *vc;
  2075. ++
  2076. ++  var = (SHELL_VAR *)NULL;
  2077. ++
  2078. ++  /* If explicitly requested, first look in the temporary environment for
  2079. ++     the variable.  This allows constructs such as "foo=x eval 'echo $foo'"
  2080. ++     to get the `exported' value of $foo.  This happens if we are executing
  2081. ++     a function or builtin, or if we are looking up a variable in a
  2082. ++     "subshell environment". */
  2083. ++  search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
  2084. ++
  2085. ++  if (search_tempenv && temporary_env)               
  2086. ++    var = hash_lookup (name, temporary_env);
  2087. ++
  2088. ++  vc = shell_variables;
  2089. ++#if 0
  2090. ++if (search_tempenv == 0 && /* (subshell_environment & SUBSHELL_COMSUB) && */
  2091. ++    expanding_redir &&
  2092. ++    (this_shell_builtin == eval_builtin || this_shell_builtin == command_builtin))
  2093. ++  {
  2094. ++  itrace("find_variable_internal: search_tempenv == 0: skipping VC_BLTNENV");
  2095. ++  while (vc && (vc->flags & VC_BLTNENV))
  2096. ++    vc = vc->down;
  2097. ++  if (vc == 0)
  2098. ++    vc = shell_variables;
  2099. ++  }
  2100. ++#endif
  2101. ++
  2102. ++  if (var == 0)
  2103. ++    var = var_lookup (name, vc);
  2104. ++
  2105. ++  if (var == 0)
  2106. ++    return ((SHELL_VAR *)NULL);
  2107. ++
  2108. ++  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  2109. ++}
  2110. ++
  2111. ++/* Look up and resolve the chain of nameref variables starting at V all the
  2112. ++   way to NULL or non-nameref. */
  2113. ++SHELL_VAR *
  2114. ++find_variable_nameref (v)
  2115. ++     SHELL_VAR *v;
  2116. ++{
  2117. ++  int level;
  2118. ++  char *newname;
  2119. ++  SHELL_VAR *orig, *oldv;
  2120. ++
  2121. ++  level = 0;
  2122. ++  orig = v;
  2123. ++  while (v && nameref_p (v))
  2124. ++    {
  2125. ++      level++;
  2126. ++      if (level > NAMEREF_MAX)
  2127. ++      return ((SHELL_VAR *)0);        /* error message here? */
  2128. ++      newname = nameref_cell (v);
  2129. ++      if (newname == 0 || *newname == '\0')
  2130. ++      return ((SHELL_VAR *)0);
  2131. ++      oldv = v;
  2132. ++      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  2133. ++      if (v == orig || v == oldv)
  2134. ++      {
  2135. ++        internal_warning (_("%s: circular name reference"), orig->name);
  2136. ++        return ((SHELL_VAR *)0);
  2137. ++      }
  2138. ++    }
  2139. ++  return v;
  2140. ++}
  2141. ++
  2142. ++/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
  2143. ++SHELL_VAR *
  2144. ++find_variable_last_nameref (name)
  2145. ++     const char *name;
  2146. ++{
  2147. ++  SHELL_VAR *v, *nv;
  2148. ++  char *newname;
  2149. ++  int level;
  2150. ++
  2151. ++  nv = v = find_variable_noref (name);
  2152. ++  level = 0;
  2153. ++  while (v && nameref_p (v))
  2154. ++    {
  2155. ++      level++;
  2156. ++      if (level > NAMEREF_MAX)
  2157. ++        return ((SHELL_VAR *)0);      /* error message here? */
  2158. ++      newname = nameref_cell (v);
  2159. ++      if (newname == 0 || *newname == '\0')
  2160. ++      return ((SHELL_VAR *)0);
  2161. ++      nv = v;
  2162. ++      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  2163. ++    }
  2164. ++  return nv;
  2165. ++}
  2166. ++
  2167. ++/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
  2168. ++SHELL_VAR *
  2169. ++find_global_variable_last_nameref (name)
  2170. ++     const char *name;
  2171. ++{
  2172. ++  SHELL_VAR *v, *nv;
  2173. ++  char *newname;
  2174. ++  int level;
  2175. ++
  2176. ++  nv = v = find_global_variable_noref (name);
  2177. ++  level = 0;
  2178. ++  while (v && nameref_p (v))
  2179. ++    {
  2180. ++      level++;
  2181. ++      if (level > NAMEREF_MAX)
  2182. ++        return ((SHELL_VAR *)0);      /* error message here? */
  2183. ++      newname = nameref_cell (v);
  2184. ++      if (newname == 0 || *newname == '\0')
  2185. ++      return ((SHELL_VAR *)0);
  2186. ++      nv = v;
  2187. ++      v = find_global_variable_noref (newname);
  2188. ++    }
  2189. ++  return nv;
  2190. ++}
  2191. ++
  2192. ++static SHELL_VAR *
  2193. ++find_nameref_at_context (v, vc)
  2194. ++     SHELL_VAR *v;
  2195. ++     VAR_CONTEXT *vc;
  2196. ++{
  2197. ++  SHELL_VAR *nv, *nv2;
  2198. ++  VAR_CONTEXT *nvc;
  2199. ++  char *newname;
  2200. ++  int level;
  2201. ++
  2202. ++  nv = v;
  2203. ++  level = 1;
  2204. ++  while (nv && nameref_p (nv))
  2205. ++    {
  2206. ++      level++;
  2207. ++      if (level > NAMEREF_MAX)
  2208. ++        return ((SHELL_VAR *)NULL);
  2209. ++      newname = nameref_cell (nv);
  2210. ++      if (newname == 0 || *newname == '\0')
  2211. ++        return ((SHELL_VAR *)NULL);      
  2212. ++      nv2 = hash_lookup (newname, vc->table);
  2213. ++      if (nv2 == 0)
  2214. ++        break;
  2215. ++      nv = nv2;
  2216. ++    }
  2217. ++  return nv;
  2218. ++}
  2219. ++
  2220. ++/* Do nameref resolution from the VC, which is the local context for some
  2221. ++   function or builtin, `up' the chain to the global variables context.  If
  2222. ++   NVCP is not NULL, return the variable context where we finally ended the
  2223. ++   nameref resolution (so the bind_variable_internal can use the correct
  2224. ++   variable context and hash table). */
  2225. ++static SHELL_VAR *
  2226. ++find_variable_nameref_context (v, vc, nvcp)
  2227. ++     SHELL_VAR *v;
  2228. ++     VAR_CONTEXT *vc;
  2229. ++     VAR_CONTEXT **nvcp;
  2230. ++{
  2231. ++  SHELL_VAR *nv, *nv2;
  2232. ++  VAR_CONTEXT *nvc;
  2233. ++
  2234. ++  /* Look starting at the current context all the way `up' */
  2235. ++  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
  2236. ++    {
  2237. ++      nv2 = find_nameref_at_context (nv, nvc);
  2238. ++      if (nv2 == 0)
  2239. ++        continue;
  2240. ++      nv = nv2;
  2241. ++      if (*nvcp)
  2242. ++        *nvcp = nvc;
  2243. ++      if (nameref_p (nv) == 0)
  2244. ++        break;
  2245. ++    }
  2246. ++  return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
  2247. ++}
  2248. ++
  2249. ++/* Do nameref resolution from the VC, which is the local context for some
  2250. ++   function or builtin, `up' the chain to the global variables context.  If
  2251. ++   NVCP is not NULL, return the variable context where we finally ended the
  2252. ++   nameref resolution (so the bind_variable_internal can use the correct
  2253. ++   variable context and hash table). */
  2254. ++static SHELL_VAR *
  2255. ++find_variable_last_nameref_context (v, vc, nvcp)
  2256. ++     SHELL_VAR *v;
  2257. ++     VAR_CONTEXT *vc;
  2258. ++     VAR_CONTEXT **nvcp;
  2259. ++{
  2260. ++  SHELL_VAR *nv, *nv2;
  2261. ++  VAR_CONTEXT *nvc;
  2262. ++
  2263. ++  /* Look starting at the current context all the way `up' */
  2264. ++  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
  2265. ++    {
  2266. ++      nv2 = find_nameref_at_context (nv, nvc);
  2267. ++      if (nv2 == 0)
  2268. ++      continue;
  2269. ++      nv = nv2;
  2270. ++      if (*nvcp)
  2271. ++        *nvcp = nvc;
  2272. ++    }
  2273. ++  return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
  2274. ++}
  2275. ++
  2276. ++/* Find a variable, forcing a search of the temporary environment first */
  2277. ++SHELL_VAR *
  2278. ++find_variable_tempenv (name)
  2279. ++     const char *name;
  2280. ++{
  2281. ++  SHELL_VAR *var;
  2282. ++
  2283. ++  var = find_variable_internal (name, 1);
  2284. ++  if (var && nameref_p (var))
  2285. ++    var = find_variable_nameref (var);
  2286. ++  return (var);
  2287. ++}
  2288. ++
  2289. ++/* Find a variable, not forcing a search of the temporary environment first */
  2290. ++SHELL_VAR *
  2291. ++find_variable_notempenv (name)
  2292. ++     const char *name;
  2293. ++{
  2294. ++  SHELL_VAR *var;
  2295. ++
  2296. ++  var = find_variable_internal (name, 0);
  2297. ++  if (var && nameref_p (var))
  2298. ++    var = find_variable_nameref (var);
  2299. ++  return (var);
  2300. ++}
  2301. ++
  2302. ++SHELL_VAR *
  2303. ++find_global_variable (name)
  2304. ++     const char *name;
  2305. ++{
  2306. ++  SHELL_VAR *var;
  2307. ++
  2308. ++  var = var_lookup (name, global_variables);
  2309. ++  if (var && nameref_p (var))
  2310. ++    var = find_variable_nameref (var);
  2311. ++
  2312. ++  if (var == 0)
  2313. ++    return ((SHELL_VAR *)NULL);
  2314. ++
  2315. ++  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  2316. ++}
  2317. ++
  2318. ++SHELL_VAR *
  2319. ++find_global_variable_noref (name)
  2320. ++     const char *name;
  2321. ++{
  2322. ++  SHELL_VAR *var;
  2323. ++
  2324. ++  var = var_lookup (name, global_variables);
  2325. ++
  2326. ++  if (var == 0)
  2327. ++    return ((SHELL_VAR *)NULL);
  2328. ++
  2329. ++  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  2330. ++}
  2331. ++
  2332. ++SHELL_VAR *
  2333. ++find_shell_variable (name)
  2334. ++     const char *name;
  2335. ++{
  2336. ++  SHELL_VAR *var;
  2337. ++
  2338. ++  var = var_lookup (name, shell_variables);
  2339. ++  if (var && nameref_p (var))
  2340. ++    var = find_variable_nameref (var);
  2341. ++
  2342. ++  if (var == 0)
  2343. ++    return ((SHELL_VAR *)NULL);
  2344. ++
  2345. ++  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  2346. ++}
  2347. ++
  2348. ++/* Look up the variable entry named NAME.  Returns the entry or NULL. */
  2349. ++SHELL_VAR *
  2350. ++find_variable (name)
  2351. ++     const char *name;
  2352. ++{
  2353. ++  SHELL_VAR *v;
  2354. ++
  2355. ++  last_table_searched = 0;
  2356. ++  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  2357. ++  if (v && nameref_p (v))
  2358. ++    v = find_variable_nameref (v);
  2359. ++  return v;
  2360. ++}
  2361. ++
  2362. ++SHELL_VAR *
  2363. ++find_variable_noref (name)
  2364. ++     const char *name;
  2365. ++{
  2366. ++  SHELL_VAR *v;
  2367. ++
  2368. ++  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  2369. ++  return v;
  2370. ++}
  2371. ++
  2372. ++/* Look up the function entry whose name matches STRING.
  2373. ++   Returns the entry or NULL. */
  2374. ++SHELL_VAR *
  2375. ++find_function (name)
  2376. ++     const char *name;
  2377. ++{
  2378. ++  return (hash_lookup (name, shell_functions));
  2379. ++}
  2380. ++
  2381. ++/* Find the function definition for the shell function named NAME.  Returns
  2382. ++   the entry or NULL. */
  2383. ++FUNCTION_DEF *
  2384. ++find_function_def (name)
  2385. ++     const char *name;
  2386. ++{
  2387. ++#if defined (DEBUGGER)
  2388. ++  return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
  2389. ++#else
  2390. ++  return ((FUNCTION_DEF *)0);
  2391. ++#endif
  2392. ++}
  2393. ++
  2394. ++/* Return the value of VAR.  VAR is assumed to have been the result of a
  2395. ++   lookup without any subscript, if arrays are compiled into the shell. */
  2396. ++char *
  2397. ++get_variable_value (var)
  2398. ++     SHELL_VAR *var;
  2399. ++{
  2400. ++  if (var == 0)
  2401. ++    return ((char *)NULL);
  2402. ++#if defined (ARRAY_VARS)
  2403. ++  else if (array_p (var))
  2404. ++    return (array_reference (array_cell (var), 0));
  2405. ++  else if (assoc_p (var))
  2406. ++    return (assoc_reference (assoc_cell (var), "0"));
  2407. ++#endif
  2408. ++  else
  2409. ++    return (value_cell (var));
  2410. ++}
  2411. ++
  2412. ++/* Return the string value of a variable.  Return NULL if the variable
  2413. ++   doesn't exist.  Don't cons a new string.  This is a potential memory
  2414. ++   leak if the variable is found in the temporary environment.  Since
  2415. ++   functions and variables have separate name spaces, returns NULL if
  2416. ++   var_name is a shell function only. */
  2417. ++char *
  2418. ++get_string_value (var_name)
  2419. ++     const char *var_name;
  2420. ++{
  2421. ++  SHELL_VAR *var;
  2422. ++
  2423. ++  var = find_variable (var_name);
  2424. ++  return ((var) ? get_variable_value (var) : (char *)NULL);
  2425. ++}
  2426. ++
  2427. ++/* This is present for use by the tilde and readline libraries. */
  2428. ++char *
  2429. ++sh_get_env_value (v)
  2430. ++     const char *v;
  2431. ++{
  2432. ++  return get_string_value (v);
  2433. ++}
  2434. ++
  2435. ++/* **************************************************************** */
  2436. ++/*                                                                */
  2437. ++/*              Creating and setting variables                    */
  2438. ++/*                                                                */
  2439. ++/* **************************************************************** */
  2440. ++
  2441. ++/* Set NAME to VALUE if NAME has no value. */
  2442. ++SHELL_VAR *
  2443. ++set_if_not (name, value)
  2444. ++     char *name, *value;
  2445. ++{
  2446. ++  SHELL_VAR *v;
  2447. ++
  2448. ++  if (shell_variables == 0)
  2449. ++    create_variable_tables ();
  2450. ++
  2451. ++  v = find_variable (name);
  2452. ++  if (v == 0)
  2453. ++    v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
  2454. ++  return (v);
  2455. ++}
  2456. ++
  2457. ++/* Create a local variable referenced by NAME. */
  2458. ++SHELL_VAR *
  2459. ++make_local_variable (name)
  2460. ++     const char *name;
  2461. ++{
  2462. ++  SHELL_VAR *new_var, *old_var;
  2463. ++  VAR_CONTEXT *vc;
  2464. ++  int was_tmpvar;
  2465. ++  char *tmp_value;
  2466. ++
  2467. ++  /* local foo; local foo;  is a no-op. */
  2468. ++  old_var = find_variable (name);
  2469. ++  if (old_var && local_p (old_var) && old_var->context == variable_context)
  2470. ++    return (old_var);
  2471. ++
  2472. ++  was_tmpvar = old_var && tempvar_p (old_var);
  2473. ++  /* If we're making a local variable in a shell function, the temporary env
  2474. ++     has already been merged into the function's variable context stack.  We
  2475. ++     can assume that a temporary var in the same context appears in the same
  2476. ++     VAR_CONTEXT and can safely be returned without creating a new variable
  2477. ++     (which results in duplicate names in the same VAR_CONTEXT->table */
  2478. ++  /* We can't just test tmpvar_p because variables in the temporary env given
  2479. ++     to a shell function appear in the function's local variable VAR_CONTEXT
  2480. ++     but retain their tempvar attribute.  We want temporary variables that are
  2481. ++     found in temporary_env, hence the test for last_table_searched, which is
  2482. ++     set in hash_lookup and only (so far) checked here. */
  2483. ++  if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
  2484. ++    {
  2485. ++      VUNSETATTR (old_var, att_invisible);
  2486. ++      return (old_var);
  2487. ++    }
  2488. ++  if (was_tmpvar)
  2489. ++    tmp_value = value_cell (old_var);
  2490. ++
  2491. ++  for (vc = shell_variables; vc; vc = vc->down)
  2492. ++    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  2493. ++      break;
  2494. ++
  2495. ++  if (vc == 0)
  2496. ++    {
  2497. ++      internal_error (_("make_local_variable: no function context at current scope"));
  2498. ++      return ((SHELL_VAR *)NULL);
  2499. ++    }
  2500. ++  else if (vc->table == 0)
  2501. ++    vc->table = hash_create (TEMPENV_HASH_BUCKETS);
  2502. ++
  2503. ++  /* Since this is called only from the local/declare/typeset code, we can
  2504. ++     call builtin_error here without worry (of course, it will also work
  2505. ++     for anything that sets this_command_name).  Variables with the `noassign'
  2506. ++     attribute may not be made local.  The test against old_var's context
  2507. ++     level is to disallow local copies of readonly global variables (since I
  2508. ++     believe that this could be a security hole).  Readonly copies of calling
  2509. ++     function local variables are OK. */
  2510. ++  if (old_var && (noassign_p (old_var) ||
  2511. ++               (readonly_p (old_var) && old_var->context == 0)))
  2512. ++    {
  2513. ++      if (readonly_p (old_var))
  2514. ++      sh_readonly (name);
  2515. ++      else if (noassign_p (old_var))
  2516. ++      builtin_error (_("%s: variable may not be assigned value"), name);
  2517. ++#if 0
  2518. ++      /* Let noassign variables through with a warning */
  2519. ++      if (readonly_p (old_var))
  2520. ++#endif
  2521. ++      return ((SHELL_VAR *)NULL);
  2522. ++    }
  2523. ++
  2524. ++  if (old_var == 0)
  2525. ++    new_var = make_new_variable (name, vc->table);
  2526. ++  else
  2527. ++    {
  2528. ++      new_var = make_new_variable (name, vc->table);
  2529. ++
  2530. ++      /* If we found this variable in one of the temporary environments,
  2531. ++       inherit its value.  Watch to see if this causes problems with
  2532. ++       things like `x=4 local x'. XXX - see above for temporary env
  2533. ++       variables with the same context level as variable_context */
  2534. ++      /* XXX - we should only do this if the variable is not an array. */
  2535. ++      if (was_tmpvar)
  2536. ++      var_setvalue (new_var, savestring (tmp_value));
  2537. ++
  2538. ++      new_var->attributes = exported_p (old_var) ? att_exported : 0;
  2539. ++    }
  2540. ++
  2541. ++  vc->flags |= VC_HASLOCAL;
  2542. ++
  2543. ++  new_var->context = variable_context;
  2544. ++  VSETATTR (new_var, att_local);
  2545. ++
  2546. ++  if (ifsname (name))
  2547. ++    setifs (new_var);
  2548. ++
  2549. ++  if (was_tmpvar == 0)
  2550. ++    VSETATTR (new_var, att_invisible);        /* XXX */
  2551. ++  return (new_var);
  2552. ++}
  2553. ++
  2554. ++/* Create a new shell variable with name NAME. */
  2555. ++static SHELL_VAR *
  2556. ++new_shell_variable (name)
  2557. ++     const char *name;
  2558. ++{
  2559. ++  SHELL_VAR *entry;
  2560. ++
  2561. ++  entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  2562. ++
  2563. ++  entry->name = savestring (name);
  2564. ++  var_setvalue (entry, (char *)NULL);
  2565. ++  CLEAR_EXPORTSTR (entry);
  2566. ++
  2567. ++  entry->dynamic_value = (sh_var_value_func_t *)NULL;
  2568. ++  entry->assign_func = (sh_var_assign_func_t *)NULL;
  2569. ++
  2570. ++  entry->attributes = 0;
  2571. ++
  2572. ++  /* Always assume variables are to be made at toplevel!
  2573. ++     make_local_variable has the responsibility of changing the
  2574. ++     variable context. */
  2575. ++  entry->context = 0;
  2576. ++
  2577. ++  return (entry);
  2578. ++}
  2579. ++
  2580. ++/* Create a new shell variable with name NAME and add it to the hash table
  2581. ++   TABLE. */
  2582. ++static SHELL_VAR *
  2583. ++make_new_variable (name, table)
  2584. ++     const char *name;
  2585. ++     HASH_TABLE *table;
  2586. ++{
  2587. ++  SHELL_VAR *entry;
  2588. ++  BUCKET_CONTENTS *elt;
  2589. ++
  2590. ++  entry = new_shell_variable (name);
  2591. ++
  2592. ++  /* Make sure we have a shell_variables hash table to add to. */
  2593. ++  if (shell_variables == 0)
  2594. ++    create_variable_tables ();
  2595. ++
  2596. ++  elt = hash_insert (savestring (name), table, HASH_NOSRCH);
  2597. ++  elt->data = (PTR_T)entry;
  2598. ++
  2599. ++  return entry;
  2600. ++}
  2601. ++
  2602. ++#if defined (ARRAY_VARS)
  2603. ++SHELL_VAR *
  2604. ++make_new_array_variable (name)
  2605. ++     char *name;
  2606. ++{
  2607. ++  SHELL_VAR *entry;
  2608. ++  ARRAY *array;
  2609. ++
  2610. ++  entry = make_new_variable (name, global_variables->table);
  2611. ++  array = array_create ();
  2612. ++
  2613. ++  var_setarray (entry, array);
  2614. ++  VSETATTR (entry, att_array);
  2615. ++  return entry;
  2616. ++}
  2617. ++
  2618. ++SHELL_VAR *
  2619. ++make_local_array_variable (name, assoc_ok)
  2620. ++     char *name;
  2621. ++     int assoc_ok;
  2622. ++{
  2623. ++  SHELL_VAR *var;
  2624. ++  ARRAY *array;
  2625. ++
  2626. ++  var = make_local_variable (name);
  2627. ++  if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
  2628. ++    return var;
  2629. ++
  2630. ++  array = array_create ();
  2631. ++
  2632. ++  dispose_variable_value (var);
  2633. ++  var_setarray (var, array);
  2634. ++  VSETATTR (var, att_array);
  2635. ++  return var;
  2636. ++}
  2637. ++
  2638. ++SHELL_VAR *
  2639. ++make_new_assoc_variable (name)
  2640. ++     char *name;
  2641. ++{
  2642. ++  SHELL_VAR *entry;
  2643. ++  HASH_TABLE *hash;
  2644. ++
  2645. ++  entry = make_new_variable (name, global_variables->table);
  2646. ++  hash = assoc_create (0);
  2647. ++
  2648. ++  var_setassoc (entry, hash);
  2649. ++  VSETATTR (entry, att_assoc);
  2650. ++  return entry;
  2651. ++}
  2652. ++
  2653. ++SHELL_VAR *
  2654. ++make_local_assoc_variable (name)
  2655. ++     char *name;
  2656. ++{
  2657. ++  SHELL_VAR *var;
  2658. ++  HASH_TABLE *hash;
  2659. ++
  2660. ++  var = make_local_variable (name);
  2661. ++  if (var == 0 || assoc_p (var))
  2662. ++    return var;
  2663. ++
  2664. ++  dispose_variable_value (var);
  2665. ++  hash = assoc_create (0);
  2666. ++
  2667. ++  var_setassoc (var, hash);
  2668. ++  VSETATTR (var, att_assoc);
  2669. ++  return var;
  2670. ++}
  2671. ++#endif
  2672. ++
  2673. ++char *
  2674. ++make_variable_value (var, value, flags)
  2675. ++     SHELL_VAR *var;
  2676. ++     char *value;
  2677. ++     int flags;
  2678. ++{
  2679. ++  char *retval, *oval;
  2680. ++  intmax_t lval, rval;
  2681. ++  int expok, olen, op;
  2682. ++
  2683. ++  /* If this variable has had its type set to integer (via `declare -i'),
  2684. ++     then do expression evaluation on it and store the result.  The
  2685. ++     functions in expr.c (evalexp()) and bind_int_variable() are responsible
  2686. ++     for turning off the integer flag if they don't want further
  2687. ++     evaluation done. */
  2688. ++  if (integer_p (var))
  2689. ++    {
  2690. ++      if (flags & ASS_APPEND)
  2691. ++      {
  2692. ++        oval = value_cell (var);
  2693. ++        lval = evalexp (oval, &expok);        /* ksh93 seems to do this */
  2694. ++        if (expok == 0)
  2695. ++          {
  2696. ++            top_level_cleanup ();
  2697. ++            jump_to_top_level (DISCARD);
  2698. ++          }
  2699. ++      }
  2700. ++      rval = evalexp (value, &expok);
  2701. ++      if (expok == 0)
  2702. ++      {
  2703. ++        top_level_cleanup ();
  2704. ++        jump_to_top_level (DISCARD);
  2705. ++      }
  2706. ++      /* This can be fooled if the variable's value changes while evaluating
  2707. ++       `rval'.  We can change it if we move the evaluation of lval to here. */
  2708. ++      if (flags & ASS_APPEND)
  2709. ++      rval += lval;
  2710. ++      retval = itos (rval);
  2711. ++    }
  2712. ++#if defined (CASEMOD_ATTRS)
  2713. ++  else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
  2714. ++    {
  2715. ++      if (flags & ASS_APPEND)
  2716. ++      {
  2717. ++        oval = get_variable_value (var);
  2718. ++        if (oval == 0)        /* paranoia */
  2719. ++          oval = "";
  2720. ++        olen = STRLEN (oval);
  2721. ++        retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
  2722. ++        strcpy (retval, oval);
  2723. ++        if (value)
  2724. ++          strcpy (retval+olen, value);
  2725. ++      }
  2726. ++      else if (*value)
  2727. ++      retval = savestring (value);
  2728. ++      else
  2729. ++      {
  2730. ++        retval = (char *)xmalloc (1);
  2731. ++        retval[0] = '\0';
  2732. ++      }
  2733. ++      op = capcase_p (var) ? CASE_CAPITALIZE
  2734. ++                       : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
  2735. ++      oval = sh_modcase (retval, (char *)0, op);
  2736. ++      free (retval);
  2737. ++      retval = oval;
  2738. ++    }
  2739. ++#endif /* CASEMOD_ATTRS */
  2740. ++  else if (value)
  2741. ++    {
  2742. ++      if (flags & ASS_APPEND)
  2743. ++      {
  2744. ++        oval = get_variable_value (var);
  2745. ++        if (oval == 0)        /* paranoia */
  2746. ++          oval = "";
  2747. ++        olen = STRLEN (oval);
  2748. ++        retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
  2749. ++        strcpy (retval, oval);
  2750. ++        if (value)
  2751. ++          strcpy (retval+olen, value);
  2752. ++      }
  2753. ++      else if (*value)
  2754. ++      retval = savestring (value);
  2755. ++      else
  2756. ++      {
  2757. ++        retval = (char *)xmalloc (1);
  2758. ++        retval[0] = '\0';
  2759. ++      }
  2760. ++    }
  2761. ++  else
  2762. ++    retval = (char *)NULL;
  2763. ++
  2764. ++  return retval;
  2765. ++}
  2766. ++
  2767. ++/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
  2768. ++   temporary environment (but usually is not). */
  2769. ++static SHELL_VAR *
  2770. ++bind_variable_internal (name, value, table, hflags, aflags)
  2771. ++     const char *name;
  2772. ++     char *value;
  2773. ++     HASH_TABLE *table;
  2774. ++     int hflags, aflags;
  2775. ++{
  2776. ++  char *newval;
  2777. ++  SHELL_VAR *entry;
  2778. ++
  2779. ++  entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
  2780. ++  /* Follow the nameref chain here if this is the global variables table */
  2781. ++  if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
  2782. ++    {
  2783. ++      entry = find_global_variable (entry->name);
  2784. ++      /* Let's see if we have a nameref referencing a variable that hasn't yet
  2785. ++       been created. */
  2786. ++      if (entry == 0)
  2787. ++      entry = find_variable_last_nameref (name);      /* XXX */
  2788. ++      if (entry == 0)                                 /* just in case */
  2789. ++        return (entry);
  2790. ++    }
  2791. ++
  2792. ++  /* The first clause handles `declare -n ref; ref=x;' */
  2793. ++  if (entry && invisible_p (entry) && nameref_p (entry))
  2794. ++    goto assign_value;
  2795. ++  else if (entry && nameref_p (entry))
  2796. ++    {
  2797. ++      newval = nameref_cell (entry);
  2798. ++#if defined (ARRAY_VARS)
  2799. ++      /* declare -n foo=x[2] */
  2800. ++      if (valid_array_reference (newval))
  2801. ++        /* XXX - should it be aflags? */
  2802. ++      entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
  2803. ++      else
  2804. ++#endif
  2805. ++      {
  2806. ++      entry = make_new_variable (newval, table);
  2807. ++      var_setvalue (entry, make_variable_value (entry, value, 0));
  2808. ++      }
  2809. ++    }
  2810. ++  else if (entry == 0)
  2811. ++    {
  2812. ++      entry = make_new_variable (name, table);
  2813. ++      var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
  2814. ++    }
  2815. ++  else if (entry->assign_func)        /* array vars have assign functions now */
  2816. ++    {
  2817. ++      INVALIDATE_EXPORTSTR (entry);
  2818. ++      newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
  2819. ++      if (assoc_p (entry))
  2820. ++      entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
  2821. ++      else if (array_p (entry))
  2822. ++      entry = (*(entry->assign_func)) (entry, newval, 0, 0);
  2823. ++      else
  2824. ++      entry = (*(entry->assign_func)) (entry, newval, -1, 0);
  2825. ++      if (newval != value)
  2826. ++      free (newval);
  2827. ++      return (entry);
  2828. ++    }
  2829. ++  else
  2830. ++    {
  2831. ++assign_value:
  2832. ++      if (readonly_p (entry) || noassign_p (entry))
  2833. ++      {
  2834. ++        if (readonly_p (entry))
  2835. ++          err_readonly (name);
  2836. ++        return (entry);
  2837. ++      }
  2838. ++
  2839. ++      /* Variables which are bound are visible. */
  2840. ++      VUNSETATTR (entry, att_invisible);
  2841. ++
  2842. ++#if defined (ARRAY_VARS)
  2843. ++      if (assoc_p (entry) || array_p (entry))
  2844. ++        newval = make_array_variable_value (entry, 0, "0", value, aflags);
  2845. ++      else
  2846. ++#endif
  2847. ++
  2848. ++      newval = make_variable_value (entry, value, aflags);    /* XXX */
  2849. ++
  2850. ++      /* Invalidate any cached export string */
  2851. ++      INVALIDATE_EXPORTSTR (entry);
  2852. ++
  2853. ++#if defined (ARRAY_VARS)
  2854. ++      /* XXX -- this bears looking at again -- XXX */
  2855. ++      /* If an existing array variable x is being assigned to with x=b or
  2856. ++       `read x' or something of that nature, silently convert it to
  2857. ++       x[0]=b or `read x[0]'. */
  2858. ++      if (assoc_p (entry))
  2859. ++      {
  2860. ++        assoc_insert (assoc_cell (entry), savestring ("0"), newval);
  2861. ++        free (newval);
  2862. ++      }
  2863. ++      else if (array_p (entry))
  2864. ++      {
  2865. ++        array_insert (array_cell (entry), 0, newval);
  2866. ++        free (newval);
  2867. ++      }
  2868. ++      else
  2869. ++#endif
  2870. ++      {
  2871. ++        FREE (value_cell (entry));
  2872. ++        var_setvalue (entry, newval);
  2873. ++      }
  2874. ++    }
  2875. ++
  2876. ++  if (mark_modified_vars)
  2877. ++    VSETATTR (entry, att_exported);
  2878. ++
  2879. ++  if (exported_p (entry))
  2880. ++    array_needs_making = 1;
  2881. ++
  2882. ++  return (entry);
  2883. ++}
  2884. ++     
  2885. ++/* Bind a variable NAME to VALUE.  This conses up the name
  2886. ++   and value strings.  If we have a temporary environment, we bind there
  2887. ++   first, then we bind into shell_variables. */
  2888. ++
  2889. ++SHELL_VAR *
  2890. ++bind_variable (name, value, flags)
  2891. ++     const char *name;
  2892. ++     char *value;
  2893. ++     int flags;
  2894. ++{
  2895. ++  SHELL_VAR *v, *nv;
  2896. ++  VAR_CONTEXT *vc, *nvc;
  2897. ++  int level;
  2898. ++
  2899. ++  if (shell_variables == 0)
  2900. ++    create_variable_tables ();
  2901. ++
  2902. ++  /* If we have a temporary environment, look there first for the variable,
  2903. ++     and, if found, modify the value there before modifying it in the
  2904. ++     shell_variables table.  This allows sourced scripts to modify values
  2905. ++     given to them in a temporary environment while modifying the variable
  2906. ++     value that the caller sees. */
  2907. ++  if (temporary_env)
  2908. ++    bind_tempenv_variable (name, value);
  2909. ++
  2910. ++  /* XXX -- handle local variables here. */
  2911. ++  for (vc = shell_variables; vc; vc = vc->down)
  2912. ++    {
  2913. ++      if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
  2914. ++      {
  2915. ++        v = hash_lookup (name, vc->table);
  2916. ++        nvc = vc;
  2917. ++        if (v && nameref_p (v))
  2918. ++          {
  2919. ++            nv = find_variable_nameref_context (v, vc, &nvc);
  2920. ++            if (nv == 0)
  2921. ++              {
  2922. ++                nv = find_variable_last_nameref_context (v, vc, &nvc);
  2923. ++                if (nv && nameref_p (nv))
  2924. ++                  {
  2925. ++                    /* If this nameref variable doesn't have a value yet,
  2926. ++                       set the value.  Otherwise, assign using the value as
  2927. ++                       normal. */
  2928. ++                    if (nameref_cell (nv) == 0)
  2929. ++                      return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
  2930. ++                    return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
  2931. ++                  }
  2932. ++                else
  2933. ++                  v = nv;
  2934. ++              }
  2935. ++            else
  2936. ++              v = nv;
  2937. ++          }
  2938. ++        if (v)
  2939. ++          return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
  2940. ++      }
  2941. ++    }
  2942. ++  /* bind_variable_internal will handle nameref resolution in this case */
  2943. ++  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
  2944. ++}
  2945. ++
  2946. ++SHELL_VAR *
  2947. ++bind_global_variable (name, value, flags)
  2948. ++     const char *name;
  2949. ++     char *value;
  2950. ++     int flags;
  2951. ++{
  2952. ++  SHELL_VAR *v, *nv;
  2953. ++  VAR_CONTEXT *vc, *nvc;
  2954. ++  int level;
  2955. ++
  2956. ++  if (shell_variables == 0)
  2957. ++    create_variable_tables ();
  2958. ++
  2959. ++  /* bind_variable_internal will handle nameref resolution in this case */
  2960. ++  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
  2961. ++}
  2962. ++
  2963. ++/* Make VAR, a simple shell variable, have value VALUE.  Once assigned a
  2964. ++   value, variables are no longer invisible.  This is a duplicate of part
  2965. ++   of the internals of bind_variable.  If the variable is exported, or
  2966. ++   all modified variables should be exported, mark the variable for export
  2967. ++   and note that the export environment needs to be recreated. */
  2968. ++SHELL_VAR *
  2969. ++bind_variable_value (var, value, aflags)
  2970. ++     SHELL_VAR *var;
  2971. ++     char *value;
  2972. ++     int aflags;
  2973. ++{
  2974. ++  char *t;
  2975. ++  int invis;
  2976. ++
  2977. ++  invis = invisible_p (var);
  2978. ++  VUNSETATTR (var, att_invisible);
  2979. ++
  2980. ++  if (var->assign_func)
  2981. ++    {
  2982. ++      /* If we're appending, we need the old value, so use
  2983. ++       make_variable_value */
  2984. ++      t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
  2985. ++      (*(var->assign_func)) (var, t, -1, 0);
  2986. ++      if (t != value && t)
  2987. ++      free (t);      
  2988. ++    }
  2989. ++  else
  2990. ++    {
  2991. ++      t = make_variable_value (var, value, aflags);
  2992. ++#if defined (ARRAY_VARS)
  2993. ++      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
  2994. ++#else
  2995. ++      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
  2996. ++#endif
  2997. ++      {
  2998. ++        free (t);
  2999. ++        if (invis)
  3000. ++          VSETATTR (var, att_invisible);      /* XXX */
  3001. ++        return ((SHELL_VAR *)NULL);
  3002. ++      }
  3003. ++      FREE (value_cell (var));
  3004. ++      var_setvalue (var, t);
  3005. ++    }
  3006. ++
  3007. ++  INVALIDATE_EXPORTSTR (var);
  3008. ++
  3009. ++  if (mark_modified_vars)
  3010. ++    VSETATTR (var, att_exported);
  3011. ++
  3012. ++  if (exported_p (var))
  3013. ++    array_needs_making = 1;
  3014. ++
  3015. ++  return (var);
  3016. ++}
  3017. ++
  3018. ++/* Bind/create a shell variable with the name LHS to the RHS.
  3019. ++   This creates or modifies a variable such that it is an integer.
  3020. ++
  3021. ++   This used to be in expr.c, but it is here so that all of the
  3022. ++   variable binding stuff is localized.  Since we don't want any
  3023. ++   recursive evaluation from bind_variable() (possible without this code,
  3024. ++   since bind_variable() calls the evaluator for variables with the integer
  3025. ++   attribute set), we temporarily turn off the integer attribute for each
  3026. ++   variable we set here, then turn it back on after binding as necessary. */
  3027. ++
  3028. ++SHELL_VAR *
  3029. ++bind_int_variable (lhs, rhs)
  3030. ++     char *lhs, *rhs;
  3031. ++{
  3032. ++  register SHELL_VAR *v;
  3033. ++  int isint, isarr, implicitarray;
  3034. ++
  3035. ++  isint = isarr = implicitarray = 0;
  3036. ++#if defined (ARRAY_VARS)
  3037. ++  if (valid_array_reference (lhs))
  3038. ++    {
  3039. ++      isarr = 1;
  3040. ++      v = array_variable_part (lhs, (char **)0, (int *)0);
  3041. ++    }
  3042. ++  else
  3043. ++#endif
  3044. ++    v = find_variable (lhs);
  3045. ++
  3046. ++  if (v)
  3047. ++    {
  3048. ++      isint = integer_p (v);
  3049. ++      VUNSETATTR (v, att_integer);
  3050. ++#if defined (ARRAY_VARS)
  3051. ++      if (array_p (v) && isarr == 0)
  3052. ++      implicitarray = 1;
  3053. ++#endif
  3054. ++    }
  3055. ++
  3056. ++#if defined (ARRAY_VARS)
  3057. ++  if (isarr)
  3058. ++    v = assign_array_element (lhs, rhs, 0);
  3059. ++  else if (implicitarray)
  3060. ++    v = bind_array_variable (lhs, 0, rhs, 0);
  3061. ++  else
  3062. ++#endif
  3063. ++    v = bind_variable (lhs, rhs, 0);
  3064. ++
  3065. ++  if (v && isint)
  3066. ++    VSETATTR (v, att_integer);
  3067. ++
  3068. ++  VUNSETATTR (v, att_invisible);
  3069. ++
  3070. ++  return (v);
  3071. ++}
  3072. ++
  3073. ++SHELL_VAR *
  3074. ++bind_var_to_int (var, val)
  3075. ++     char *var;
  3076. ++     intmax_t val;
  3077. ++{
  3078. ++  char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
  3079. ++
  3080. ++  p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
  3081. ++  return (bind_int_variable (var, p));
  3082. ++}
  3083. ++
  3084. ++/* Do a function binding to a variable.  You pass the name and
  3085. ++   the command to bind to.  This conses the name and command. */
  3086. ++SHELL_VAR *
  3087. ++bind_function (name, value)
  3088. ++     const char *name;
  3089. ++     COMMAND *value;
  3090. ++{
  3091. ++  SHELL_VAR *entry;
  3092. ++
  3093. ++  entry = find_function (name);
  3094. ++  if (entry == 0)
  3095. ++    {
  3096. ++      BUCKET_CONTENTS *elt;
  3097. ++
  3098. ++      elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
  3099. ++      entry = new_shell_variable (name);
  3100. ++      elt->data = (PTR_T)entry;
  3101. ++    }
  3102. ++  else
  3103. ++    INVALIDATE_EXPORTSTR (entry);
  3104. ++
  3105. ++  if (var_isset (entry))
  3106. ++    dispose_command (function_cell (entry));
  3107. ++
  3108. ++  if (value)
  3109. ++    var_setfunc (entry, copy_command (value));
  3110. ++  else
  3111. ++    var_setfunc (entry, 0);
  3112. ++
  3113. ++  VSETATTR (entry, att_function);
  3114. ++
  3115. ++  if (mark_modified_vars)
  3116. ++    VSETATTR (entry, att_exported);
  3117. ++
  3118. ++  VUNSETATTR (entry, att_invisible);          /* Just to be sure */
  3119. ++
  3120. ++  if (exported_p (entry))
  3121. ++    array_needs_making = 1;
  3122. ++
  3123. ++#if defined (PROGRAMMABLE_COMPLETION)
  3124. ++  set_itemlist_dirty (&it_functions);
  3125. ++#endif
  3126. ++
  3127. ++  return (entry);
  3128. ++}
  3129. ++
  3130. ++#if defined (DEBUGGER)
  3131. ++/* Bind a function definition, which includes source file and line number
  3132. ++   information in addition to the command, into the FUNCTION_DEF hash table.*/
  3133. ++void
  3134. ++bind_function_def (name, value)
  3135. ++     const char *name;
  3136. ++     FUNCTION_DEF *value;
  3137. ++{
  3138. ++  FUNCTION_DEF *entry;
  3139. ++  BUCKET_CONTENTS *elt;
  3140. ++  COMMAND *cmd;
  3141. ++
  3142. ++  entry = find_function_def (name);
  3143. ++  if (entry)
  3144. ++    {
  3145. ++      dispose_function_def_contents (entry);
  3146. ++      entry = copy_function_def_contents (value, entry);
  3147. ++    }
  3148. ++  else
  3149. ++    {
  3150. ++      cmd = value->command;
  3151. ++      value->command = 0;
  3152. ++      entry = copy_function_def (value);
  3153. ++      value->command = cmd;
  3154. ++
  3155. ++      elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
  3156. ++      elt->data = (PTR_T *)entry;
  3157. ++    }
  3158. ++}
  3159. ++#endif /* DEBUGGER */
  3160. ++
  3161. ++/* Add STRING, which is of the form foo=bar, to the temporary environment
  3162. ++   HASH_TABLE (temporary_env).  The functions in execute_cmd.c are
  3163. ++   responsible for moving the main temporary env to one of the other
  3164. ++   temporary environments.  The expansion code in subst.c calls this. */
  3165. ++int
  3166. ++assign_in_env (word, flags)
  3167. ++     WORD_DESC *word;
  3168. ++     int flags;
  3169. ++{
  3170. ++  int offset, aflags;
  3171. ++  char *name, *temp, *value;
  3172. ++  SHELL_VAR *var;
  3173. ++  const char *string;
  3174. ++
  3175. ++  string = word->word;
  3176. ++
  3177. ++  aflags = 0;
  3178. ++  offset = assignment (string, 0);
  3179. ++  name = savestring (string);
  3180. ++  value = (char *)NULL;
  3181. ++
  3182. ++  if (name[offset] == '=')
  3183. ++    {
  3184. ++      name[offset] = 0;
  3185. ++
  3186. ++      /* don't ignore the `+' when assigning temporary environment */
  3187. ++      if (name[offset - 1] == '+')
  3188. ++      {
  3189. ++        name[offset - 1] = '\0';
  3190. ++        aflags |= ASS_APPEND;
  3191. ++      }
  3192. ++
  3193. ++      var = find_variable (name);
  3194. ++      if (var && (readonly_p (var) || noassign_p (var)))
  3195. ++      {
  3196. ++        if (readonly_p (var))
  3197. ++          err_readonly (name);
  3198. ++        free (name);
  3199. ++        return (0);
  3200. ++      }
  3201. ++
  3202. ++      temp = name + offset + 1;
  3203. ++      value = expand_assignment_string_to_string (temp, 0);
  3204. ++
  3205. ++      if (var && (aflags & ASS_APPEND))
  3206. ++      {
  3207. ++        temp = make_variable_value (var, value, aflags);
  3208. ++        FREE (value);
  3209. ++        value = temp;
  3210. ++      }
  3211. ++    }
  3212. ++
  3213. ++  if (temporary_env == 0)
  3214. ++    temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
  3215. ++
  3216. ++  var = hash_lookup (name, temporary_env);
  3217. ++  if (var == 0)
  3218. ++    var = make_new_variable (name, temporary_env);
  3219. ++  else
  3220. ++    FREE (value_cell (var));
  3221. ++
  3222. ++  if (value == 0)
  3223. ++    {
  3224. ++      value = (char *)xmalloc (1);    /* like do_assignment_internal */
  3225. ++      value[0] = '\0';
  3226. ++    }
  3227. ++
  3228. ++  var_setvalue (var, value);
  3229. ++  var->attributes |= (att_exported|att_tempvar);
  3230. ++  var->context = variable_context;    /* XXX */
  3231. ++
  3232. ++  INVALIDATE_EXPORTSTR (var);
  3233. ++  var->exportstr = mk_env_string (name, value, 0);
  3234. ++
  3235. ++  array_needs_making = 1;
  3236. ++
  3237. ++  if (flags)
  3238. ++    stupidly_hack_special_variables (name);
  3239. ++
  3240. ++  if (echo_command_at_execute)
  3241. ++    /* The Korn shell prints the `+ ' in front of assignment statements,
  3242. ++      so we do too. */
  3243. ++    xtrace_print_assignment (name, value, 0, 1);
  3244. ++
  3245. ++  free (name);
  3246. ++  return 1;
  3247. ++}
  3248. ++
  3249. ++/* **************************************************************** */
  3250. ++/*                                                                */
  3251. ++/*                    Copying variables                           */
  3252. ++/*                                                                */
  3253. ++/* **************************************************************** */
  3254. ++
  3255. ++#ifdef INCLUDE_UNUSED
  3256. ++/* Copy VAR to a new data structure and return that structure. */
  3257. ++SHELL_VAR *
  3258. ++copy_variable (var)
  3259. ++     SHELL_VAR *var;
  3260. ++{
  3261. ++  SHELL_VAR *copy = (SHELL_VAR *)NULL;
  3262. ++
  3263. ++  if (var)
  3264. ++    {
  3265. ++      copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  3266. ++
  3267. ++      copy->attributes = var->attributes;
  3268. ++      copy->name = savestring (var->name);
  3269. ++
  3270. ++      if (function_p (var))
  3271. ++      var_setfunc (copy, copy_command (function_cell (var)));
  3272. ++#if defined (ARRAY_VARS)
  3273. ++      else if (array_p (var))
  3274. ++      var_setarray (copy, array_copy (array_cell (var)));
  3275. ++      else if (assoc_p (var))
  3276. ++      var_setassoc (copy, assoc_copy (assoc_cell (var)));
  3277. ++#endif
  3278. ++      else if (nameref_cell (var))    /* XXX - nameref */
  3279. ++      var_setref (copy, savestring (nameref_cell (var)));
  3280. ++      else if (value_cell (var))      /* XXX - nameref */
  3281. ++      var_setvalue (copy, savestring (value_cell (var)));
  3282. ++      else
  3283. ++      var_setvalue (copy, (char *)NULL);
  3284. ++
  3285. ++      copy->dynamic_value = var->dynamic_value;
  3286. ++      copy->assign_func = var->assign_func;
  3287. ++
  3288. ++      copy->exportstr = COPY_EXPORTSTR (var);
  3289. ++
  3290. ++      copy->context = var->context;
  3291. ++    }
  3292. ++  return (copy);
  3293. ++}
  3294. ++#endif
  3295. ++
  3296. ++/* **************************************************************** */
  3297. ++/*                                                                */
  3298. ++/*              Deleting and unsetting variables                  */
  3299. ++/*                                                                */
  3300. ++/* **************************************************************** */
  3301. ++
  3302. ++/* Dispose of the information attached to VAR. */
  3303. ++static void
  3304. ++dispose_variable_value (var)
  3305. ++     SHELL_VAR *var;
  3306. ++{
  3307. ++  if (function_p (var))
  3308. ++    dispose_command (function_cell (var));
  3309. ++#if defined (ARRAY_VARS)
  3310. ++  else if (array_p (var))
  3311. ++    array_dispose (array_cell (var));
  3312. ++  else if (assoc_p (var))
  3313. ++    assoc_dispose (assoc_cell (var));
  3314. ++#endif
  3315. ++  else if (nameref_p (var))
  3316. ++    FREE (nameref_cell (var));
  3317. ++  else
  3318. ++    FREE (value_cell (var));
  3319. ++}
  3320. ++
  3321. ++void
  3322. ++dispose_variable (var)
  3323. ++     SHELL_VAR *var;
  3324. ++{
  3325. ++  if (var == 0)
  3326. ++    return;
  3327. ++
  3328. ++  if (nofree_p (var) == 0)
  3329. ++    dispose_variable_value (var);
  3330. ++
  3331. ++  FREE_EXPORTSTR (var);
  3332. ++
  3333. ++  free (var->name);
  3334. ++
  3335. ++  if (exported_p (var))
  3336. ++    array_needs_making = 1;
  3337. ++
  3338. ++  free (var);
  3339. ++}
  3340. ++
  3341. ++/* Unset the shell variable referenced by NAME.  Unsetting a nameref variable
  3342. ++   unsets the variable it resolves to but leaves the nameref alone. */
  3343. ++int
  3344. ++unbind_variable (name)
  3345. ++     const char *name;
  3346. ++{
  3347. ++  SHELL_VAR *v, *nv;
  3348. ++  int r;
  3349. ++
  3350. ++  v = var_lookup (name, shell_variables);
  3351. ++  nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
  3352. ++
  3353. ++  r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
  3354. ++  return r;
  3355. ++}
  3356. ++
  3357. ++/* Unbind NAME, where NAME is assumed to be a nameref variable */
  3358. ++int
  3359. ++unbind_nameref (name)
  3360. ++     const char *name;
  3361. ++{
  3362. ++  SHELL_VAR *v;
  3363. ++
  3364. ++  v = var_lookup (name, shell_variables);
  3365. ++  if (v && nameref_p (v))
  3366. ++    return makunbound (name, shell_variables);
  3367. ++  return 0;
  3368. ++}
  3369. ++
  3370. ++/* Unset the shell function named NAME. */
  3371. ++int
  3372. ++unbind_func (name)
  3373. ++     const char *name;
  3374. ++{
  3375. ++  BUCKET_CONTENTS *elt;
  3376. ++  SHELL_VAR *func;
  3377. ++
  3378. ++  elt = hash_remove (name, shell_functions, 0);
  3379. ++
  3380. ++  if (elt == 0)
  3381. ++    return -1;
  3382. ++
  3383. ++#if defined (PROGRAMMABLE_COMPLETION)
  3384. ++  set_itemlist_dirty (&it_functions);
  3385. ++#endif
  3386. ++
  3387. ++  func = (SHELL_VAR *)elt->data;
  3388. ++  if (func)
  3389. ++    {
  3390. ++      if (exported_p (func))
  3391. ++      array_needs_making++;
  3392. ++      dispose_variable (func);
  3393. ++    }
  3394. ++
  3395. ++  free (elt->key);
  3396. ++  free (elt);
  3397. ++
  3398. ++  return 0;  
  3399. ++}
  3400. ++
  3401. ++#if defined (DEBUGGER)
  3402. ++int
  3403. ++unbind_function_def (name)
  3404. ++     const char *name;
  3405. ++{
  3406. ++  BUCKET_CONTENTS *elt;
  3407. ++  FUNCTION_DEF *funcdef;
  3408. ++
  3409. ++  elt = hash_remove (name, shell_function_defs, 0);
  3410. ++
  3411. ++  if (elt == 0)
  3412. ++    return -1;
  3413. ++
  3414. ++  funcdef = (FUNCTION_DEF *)elt->data;
  3415. ++  if (funcdef)
  3416. ++    dispose_function_def (funcdef);
  3417. ++
  3418. ++  free (elt->key);
  3419. ++  free (elt);
  3420. ++
  3421. ++  return 0;  
  3422. ++}
  3423. ++#endif /* DEBUGGER */
  3424. ++
  3425. ++int
  3426. ++delete_var (name, vc)
  3427. ++     const char *name;
  3428. ++     VAR_CONTEXT *vc;
  3429. ++{
  3430. ++  BUCKET_CONTENTS *elt;
  3431. ++  SHELL_VAR *old_var;
  3432. ++  VAR_CONTEXT *v;
  3433. ++
  3434. ++  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
  3435. ++    if (elt = hash_remove (name, v->table, 0))
  3436. ++      break;
  3437. ++
  3438. ++  if (elt == 0)
  3439. ++    return (-1);
  3440. ++
  3441. ++  old_var = (SHELL_VAR *)elt->data;
  3442. ++  free (elt->key);
  3443. ++  free (elt);
  3444. ++
  3445. ++  dispose_variable (old_var);
  3446. ++  return (0);
  3447. ++}
  3448. ++
  3449. ++/* Make the variable associated with NAME go away.  HASH_LIST is the
  3450. ++   hash table from which this variable should be deleted (either
  3451. ++   shell_variables or shell_functions).
  3452. ++   Returns non-zero if the variable couldn't be found. */
  3453. ++int
  3454. ++makunbound (name, vc)
  3455. ++     const char *name;
  3456. ++     VAR_CONTEXT *vc;
  3457. ++{
  3458. ++  BUCKET_CONTENTS *elt, *new_elt;
  3459. ++  SHELL_VAR *old_var;
  3460. ++  VAR_CONTEXT *v;
  3461. ++  char *t;
  3462. ++
  3463. ++  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
  3464. ++    if (elt = hash_remove (name, v->table, 0))
  3465. ++      break;
  3466. ++
  3467. ++  if (elt == 0)
  3468. ++    return (-1);
  3469. ++
  3470. ++  old_var = (SHELL_VAR *)elt->data;
  3471. ++
  3472. ++  if (old_var && exported_p (old_var))
  3473. ++    array_needs_making++;
  3474. ++
  3475. ++  /* If we're unsetting a local variable and we're still executing inside
  3476. ++     the function, just mark the variable as invisible.  The function
  3477. ++     eventually called by pop_var_context() will clean it up later.  This
  3478. ++     must be done so that if the variable is subsequently assigned a new
  3479. ++     value inside the function, the `local' attribute is still present.
  3480. ++     We also need to add it back into the correct hash table. */
  3481. ++  if (old_var && local_p (old_var) && variable_context == old_var->context)
  3482. ++    {
  3483. ++      if (nofree_p (old_var))
  3484. ++      var_setvalue (old_var, (char *)NULL);
  3485. ++#if defined (ARRAY_VARS)
  3486. ++      else if (array_p (old_var))
  3487. ++      array_dispose (array_cell (old_var));
  3488. ++      else if (assoc_p (old_var))
  3489. ++      assoc_dispose (assoc_cell (old_var));
  3490. ++#endif
  3491. ++      else if (nameref_p (old_var))
  3492. ++      FREE (nameref_cell (old_var));
  3493. ++      else
  3494. ++      FREE (value_cell (old_var));
  3495. ++      /* Reset the attributes.  Preserve the export attribute if the variable
  3496. ++       came from a temporary environment.  Make sure it stays local, and
  3497. ++       make it invisible. */
  3498. ++      old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
  3499. ++      VSETATTR (old_var, att_local);
  3500. ++      VSETATTR (old_var, att_invisible);
  3501. ++      var_setvalue (old_var, (char *)NULL);
  3502. ++      INVALIDATE_EXPORTSTR (old_var);
  3503. ++
  3504. ++      new_elt = hash_insert (savestring (old_var->name), v->table, 0);
  3505. ++      new_elt->data = (PTR_T)old_var;
  3506. ++      stupidly_hack_special_variables (old_var->name);
  3507. ++
  3508. ++      free (elt->key);
  3509. ++      free (elt);
  3510. ++      return (0);
  3511. ++    }
  3512. ++
  3513. ++  /* Have to save a copy of name here, because it might refer to
  3514. ++     old_var->name.  If so, stupidly_hack_special_variables will
  3515. ++     reference freed memory. */
  3516. ++  t = savestring (name);
  3517. ++
  3518. ++  free (elt->key);
  3519. ++  free (elt);
  3520. ++
  3521. ++  dispose_variable (old_var);
  3522. ++  stupidly_hack_special_variables (t);
  3523. ++  free (t);
  3524. ++
  3525. ++  return (0);
  3526. ++}
  3527. ++
  3528. ++/* Get rid of all of the variables in the current context. */
  3529. ++void
  3530. ++kill_all_local_variables ()
  3531. ++{
  3532. ++  VAR_CONTEXT *vc;
  3533. ++
  3534. ++  for (vc = shell_variables; vc; vc = vc->down)
  3535. ++    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  3536. ++      break;
  3537. ++  if (vc == 0)
  3538. ++    return;           /* XXX */
  3539. ++
  3540. ++  if (vc->table && vc_haslocals (vc))
  3541. ++    {
  3542. ++      delete_all_variables (vc->table);
  3543. ++      hash_dispose (vc->table);
  3544. ++    }
  3545. ++  vc->table = (HASH_TABLE *)NULL;
  3546. ++}
  3547. ++
  3548. ++static void
  3549. ++free_variable_hash_data (data)
  3550. ++     PTR_T data;
  3551. ++{
  3552. ++  SHELL_VAR *var;
  3553. ++
  3554. ++  var = (SHELL_VAR *)data;
  3555. ++  dispose_variable (var);
  3556. ++}
  3557. ++
  3558. ++/* Delete the entire contents of the hash table. */
  3559. ++void
  3560. ++delete_all_variables (hashed_vars)
  3561. ++     HASH_TABLE *hashed_vars;
  3562. ++{
  3563. ++  hash_flush (hashed_vars, free_variable_hash_data);
  3564. ++}
  3565. ++
  3566. ++/* **************************************************************** */
  3567. ++/*                                                                */
  3568. ++/*                 Setting variable attributes                    */
  3569. ++/*                                                                */
  3570. ++/* **************************************************************** */
  3571. ++
  3572. ++#define FIND_OR_MAKE_VARIABLE(name, entry) \
  3573. ++  do \
  3574. ++    { \
  3575. ++      entry = find_variable (name); \
  3576. ++      if (!entry) \
  3577. ++      { \
  3578. ++        entry = bind_variable (name, "", 0); \
  3579. ++        if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
  3580. ++      } \
  3581. ++    } \
  3582. ++  while (0)
  3583. ++
  3584. ++/* Make the variable associated with NAME be readonly.
  3585. ++   If NAME does not exist yet, create it. */
  3586. ++void
  3587. ++set_var_read_only (name)
  3588. ++     char *name;
  3589. ++{
  3590. ++  SHELL_VAR *entry;
  3591. ++
  3592. ++  FIND_OR_MAKE_VARIABLE (name, entry);
  3593. ++  VSETATTR (entry, att_readonly);
  3594. ++}
  3595. ++
  3596. ++#ifdef INCLUDE_UNUSED
  3597. ++/* Make the function associated with NAME be readonly.
  3598. ++   If NAME does not exist, we just punt, like auto_export code below. */
  3599. ++void
  3600. ++set_func_read_only (name)
  3601. ++     const char *name;
  3602. ++{
  3603. ++  SHELL_VAR *entry;
  3604. ++
  3605. ++  entry = find_function (name);
  3606. ++  if (entry)
  3607. ++    VSETATTR (entry, att_readonly);
  3608. ++}
  3609. ++
  3610. ++/* Make the variable associated with NAME be auto-exported.
  3611. ++   If NAME does not exist yet, create it. */
  3612. ++void
  3613. ++set_var_auto_export (name)
  3614. ++     char *name;
  3615. ++{
  3616. ++  SHELL_VAR *entry;
  3617. ++
  3618. ++  FIND_OR_MAKE_VARIABLE (name, entry);
  3619. ++  set_auto_export (entry);
  3620. ++}
  3621. ++
  3622. ++/* Make the function associated with NAME be auto-exported. */
  3623. ++void
  3624. ++set_func_auto_export (name)
  3625. ++     const char *name;
  3626. ++{
  3627. ++  SHELL_VAR *entry;
  3628. ++
  3629. ++  entry = find_function (name);
  3630. ++  if (entry)
  3631. ++    set_auto_export (entry);
  3632. ++}
  3633. ++#endif
  3634. ++
  3635. ++/* **************************************************************** */
  3636. ++/*                                                                */
  3637. ++/*                 Creating lists of variables                    */
  3638. ++/*                                                                */
  3639. ++/* **************************************************************** */
  3640. ++
  3641. ++static VARLIST *
  3642. ++vlist_alloc (nentries)
  3643. ++     int nentries;
  3644. ++{
  3645. ++  VARLIST  *vlist;
  3646. ++
  3647. ++  vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
  3648. ++  vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
  3649. ++  vlist->list_size = nentries;
  3650. ++  vlist->list_len = 0;
  3651. ++  vlist->list[0] = (SHELL_VAR *)NULL;
  3652. ++
  3653. ++  return vlist;
  3654. ++}
  3655. ++
  3656. ++static VARLIST *
  3657. ++vlist_realloc (vlist, n)
  3658. ++     VARLIST *vlist;
  3659. ++     int n;
  3660. ++{
  3661. ++  if (vlist == 0)
  3662. ++    return (vlist = vlist_alloc (n));
  3663. ++  if (n > vlist->list_size)
  3664. ++    {
  3665. ++      vlist->list_size = n;
  3666. ++      vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
  3667. ++    }
  3668. ++  return vlist;
  3669. ++}
  3670. ++
  3671. ++static void
  3672. ++vlist_add (vlist, var, flags)
  3673. ++     VARLIST *vlist;
  3674. ++     SHELL_VAR *var;
  3675. ++     int flags;
  3676. ++{
  3677. ++  register int i;
  3678. ++
  3679. ++  for (i = 0; i < vlist->list_len; i++)
  3680. ++    if (STREQ (var->name, vlist->list[i]->name))
  3681. ++      break;
  3682. ++  if (i < vlist->list_len)
  3683. ++    return;
  3684. ++
  3685. ++  if (i >= vlist->list_size)
  3686. ++    vlist = vlist_realloc (vlist, vlist->list_size + 16);
  3687. ++
  3688. ++  vlist->list[vlist->list_len++] = var;
  3689. ++  vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
  3690. ++}
  3691. ++
  3692. ++/* Map FUNCTION over the variables in VAR_HASH_TABLE.  Return an array of the
  3693. ++   variables for which FUNCTION returns a non-zero value.  A NULL value
  3694. ++   for FUNCTION means to use all variables. */
  3695. ++SHELL_VAR **
  3696. ++map_over (function, vc)
  3697. ++     sh_var_map_func_t *function;
  3698. ++     VAR_CONTEXT *vc;
  3699. ++{
  3700. ++  VAR_CONTEXT *v;
  3701. ++  VARLIST *vlist;
  3702. ++  SHELL_VAR **ret;
  3703. ++  int nentries;
  3704. ++
  3705. ++  for (nentries = 0, v = vc; v; v = v->down)
  3706. ++    nentries += HASH_ENTRIES (v->table);
  3707. ++
  3708. ++  if (nentries == 0)
  3709. ++    return (SHELL_VAR **)NULL;
  3710. ++
  3711. ++  vlist = vlist_alloc (nentries);
  3712. ++
  3713. ++  for (v = vc; v; v = v->down)
  3714. ++    flatten (v->table, function, vlist, 0);
  3715. ++
  3716. ++  ret = vlist->list;
  3717. ++  free (vlist);
  3718. ++  return ret;
  3719. ++}
  3720. ++
  3721. ++SHELL_VAR **
  3722. ++map_over_funcs (function)
  3723. ++     sh_var_map_func_t *function;
  3724. ++{
  3725. ++  VARLIST *vlist;
  3726. ++  SHELL_VAR **ret;
  3727. ++
  3728. ++  if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
  3729. ++    return ((SHELL_VAR **)NULL);
  3730. ++
  3731. ++  vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
  3732. ++
  3733. ++  flatten (shell_functions, function, vlist, 0);
  3734. ++
  3735. ++  ret = vlist->list;
  3736. ++  free (vlist);
  3737. ++  return ret;
  3738. ++}
  3739. ++
  3740. ++/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
  3741. ++   elements for which FUNC succeeds to VLIST->list.  FLAGS is reserved
  3742. ++   for future use.  Only unique names are added to VLIST.  If FUNC is
  3743. ++   NULL, each variable in VAR_HASH_TABLE is added to VLIST.  If VLIST is
  3744. ++   NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE.  If VLIST
  3745. ++   and FUNC are both NULL, nothing happens. */
  3746. ++static void
  3747. ++flatten (var_hash_table, func, vlist, flags)
  3748. ++     HASH_TABLE *var_hash_table;
  3749. ++     sh_var_map_func_t *func;
  3750. ++     VARLIST *vlist;
  3751. ++     int flags;
  3752. ++{
  3753. ++  register int i;
  3754. ++  register BUCKET_CONTENTS *tlist;
  3755. ++  int r;
  3756. ++  SHELL_VAR *var;
  3757. ++
  3758. ++  if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
  3759. ++    return;
  3760. ++
  3761. ++  for (i = 0; i < var_hash_table->nbuckets; i++)
  3762. ++    {
  3763. ++      for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
  3764. ++      {
  3765. ++        var = (SHELL_VAR *)tlist->data;
  3766. ++
  3767. ++        r = func ? (*func) (var) : 1;
  3768. ++        if (r && vlist)
  3769. ++          vlist_add (vlist, var, flags);
  3770. ++      }
  3771. ++    }
  3772. ++}
  3773. ++
  3774. ++void
  3775. ++sort_variables (array)
  3776. ++     SHELL_VAR **array;
  3777. ++{
  3778. ++  qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
  3779. ++}
  3780. ++
  3781. ++static int
  3782. ++qsort_var_comp (var1, var2)
  3783. ++     SHELL_VAR **var1, **var2;
  3784. ++{
  3785. ++  int result;
  3786. ++
  3787. ++  if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
  3788. ++    result = strcmp ((*var1)->name, (*var2)->name);
  3789. ++
  3790. ++  return (result);
  3791. ++}
  3792. ++
  3793. ++/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
  3794. ++   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
  3795. ++static SHELL_VAR **
  3796. ++vapply (func)
  3797. ++     sh_var_map_func_t *func;
  3798. ++{
  3799. ++  SHELL_VAR **list;
  3800. ++
  3801. ++  list = map_over (func, shell_variables);
  3802. ++  if (list /* && posixly_correct */)
  3803. ++    sort_variables (list);
  3804. ++  return (list);
  3805. ++}
  3806. ++
  3807. ++/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
  3808. ++   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
  3809. ++static SHELL_VAR **
  3810. ++fapply (func)
  3811. ++     sh_var_map_func_t *func;
  3812. ++{
  3813. ++  SHELL_VAR **list;
  3814. ++
  3815. ++  list = map_over_funcs (func);
  3816. ++  if (list /* && posixly_correct */)
  3817. ++    sort_variables (list);
  3818. ++  return (list);
  3819. ++}
  3820. ++
  3821. ++/* Create a NULL terminated array of all the shell variables. */
  3822. ++SHELL_VAR **
  3823. ++all_shell_variables ()
  3824. ++{
  3825. ++  return (vapply ((sh_var_map_func_t *)NULL));
  3826. ++}
  3827. ++
  3828. ++/* Create a NULL terminated array of all the shell functions. */
  3829. ++SHELL_VAR **
  3830. ++all_shell_functions ()
  3831. ++{
  3832. ++  return (fapply ((sh_var_map_func_t *)NULL));
  3833. ++}
  3834. ++
  3835. ++static int
  3836. ++visible_var (var)
  3837. ++     SHELL_VAR *var;
  3838. ++{
  3839. ++  return (invisible_p (var) == 0);
  3840. ++}
  3841. ++
  3842. ++SHELL_VAR **
  3843. ++all_visible_functions ()
  3844. ++{
  3845. ++  return (fapply (visible_var));
  3846. ++}
  3847. ++
  3848. ++SHELL_VAR **
  3849. ++all_visible_variables ()
  3850. ++{
  3851. ++  return (vapply (visible_var));
  3852. ++}
  3853. ++
  3854. ++/* Return non-zero if the variable VAR is visible and exported.  Array
  3855. ++   variables cannot be exported. */
  3856. ++static int
  3857. ++visible_and_exported (var)
  3858. ++     SHELL_VAR *var;
  3859. ++{
  3860. ++  return (invisible_p (var) == 0 && exported_p (var));
  3861. ++}
  3862. ++
  3863. ++/* Candidate variables for the export environment are either valid variables
  3864. ++   with the export attribute or invalid variables inherited from the initial
  3865. ++   environment and simply passed through. */
  3866. ++static int
  3867. ++export_environment_candidate (var)
  3868. ++     SHELL_VAR *var;
  3869. ++{
  3870. ++  return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
  3871. ++}
  3872. ++
  3873. ++/* Return non-zero if VAR is a local variable in the current context and
  3874. ++   is exported. */
  3875. ++static int
  3876. ++local_and_exported (var)
  3877. ++     SHELL_VAR *var;
  3878. ++{
  3879. ++  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
  3880. ++}
  3881. ++
  3882. ++SHELL_VAR **
  3883. ++all_exported_variables ()
  3884. ++{
  3885. ++  return (vapply (visible_and_exported));
  3886. ++}
  3887. ++
  3888. ++SHELL_VAR **
  3889. ++local_exported_variables ()
  3890. ++{
  3891. ++  return (vapply (local_and_exported));
  3892. ++}
  3893. ++
  3894. ++static int
  3895. ++variable_in_context (var)
  3896. ++     SHELL_VAR *var;
  3897. ++{
  3898. ++  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
  3899. ++}
  3900. ++
  3901. ++SHELL_VAR **
  3902. ++all_local_variables ()
  3903. ++{
  3904. ++  VARLIST *vlist;
  3905. ++  SHELL_VAR **ret;
  3906. ++  VAR_CONTEXT *vc;
  3907. ++
  3908. ++  vc = shell_variables;
  3909. ++  for (vc = shell_variables; vc; vc = vc->down)
  3910. ++    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  3911. ++      break;
  3912. ++
  3913. ++  if (vc == 0)
  3914. ++    {
  3915. ++      internal_error (_("all_local_variables: no function context at current scope"));
  3916. ++      return (SHELL_VAR **)NULL;
  3917. ++    }
  3918. ++  if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
  3919. ++    return (SHELL_VAR **)NULL;
  3920. ++    
  3921. ++  vlist = vlist_alloc (HASH_ENTRIES (vc->table));
  3922. ++
  3923. ++  flatten (vc->table, variable_in_context, vlist, 0);
  3924. ++
  3925. ++  ret = vlist->list;
  3926. ++  free (vlist);
  3927. ++  if (ret)
  3928. ++    sort_variables (ret);
  3929. ++  return ret;
  3930. ++}
  3931. ++
  3932. ++#if defined (ARRAY_VARS)
  3933. ++/* Return non-zero if the variable VAR is visible and an array. */
  3934. ++static int
  3935. ++visible_array_vars (var)
  3936. ++     SHELL_VAR *var;
  3937. ++{
  3938. ++  return (invisible_p (var) == 0 && array_p (var));
  3939. ++}
  3940. ++
  3941. ++SHELL_VAR **
  3942. ++all_array_variables ()
  3943. ++{
  3944. ++  return (vapply (visible_array_vars));
  3945. ++}
  3946. ++#endif /* ARRAY_VARS */
  3947. ++
  3948. ++char **
  3949. ++all_variables_matching_prefix (prefix)
  3950. ++     const char *prefix;
  3951. ++{
  3952. ++  SHELL_VAR **varlist;
  3953. ++  char **rlist;
  3954. ++  int vind, rind, plen;
  3955. ++
  3956. ++  plen = STRLEN (prefix);
  3957. ++  varlist = all_visible_variables ();
  3958. ++  for (vind = 0; varlist && varlist[vind]; vind++)
  3959. ++    ;
  3960. ++  if (varlist == 0 || vind == 0)
  3961. ++    return ((char **)NULL);
  3962. ++  rlist = strvec_create (vind + 1);
  3963. ++  for (vind = rind = 0; varlist[vind]; vind++)
  3964. ++    {
  3965. ++      if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
  3966. ++      rlist[rind++] = savestring (varlist[vind]->name);
  3967. ++    }
  3968. ++  rlist[rind] = (char *)0;
  3969. ++  free (varlist);
  3970. ++
  3971. ++  return rlist;
  3972. ++}
  3973. ++
  3974. ++/* **************************************************************** */
  3975. ++/*                                                                */
  3976. ++/*             Managing temporary variable scopes                 */
  3977. ++/*                                                                */
  3978. ++/* **************************************************************** */
  3979. ++
  3980. ++/* Make variable NAME have VALUE in the temporary environment. */
  3981. ++static SHELL_VAR *
  3982. ++bind_tempenv_variable (name, value)
  3983. ++     const char *name;
  3984. ++     char *value;
  3985. ++{
  3986. ++  SHELL_VAR *var;
  3987. ++
  3988. ++  var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
  3989. ++
  3990. ++  if (var)
  3991. ++    {
  3992. ++      FREE (value_cell (var));
  3993. ++      var_setvalue (var, savestring (value));
  3994. ++      INVALIDATE_EXPORTSTR (var);
  3995. ++    }
  3996. ++
  3997. ++  return (var);
  3998. ++}
  3999. ++
  4000. ++/* Find a variable in the temporary environment that is named NAME.
  4001. ++   Return the SHELL_VAR *, or NULL if not found. */
  4002. ++SHELL_VAR *
  4003. ++find_tempenv_variable (name)
  4004. ++     const char *name;
  4005. ++{
  4006. ++  return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
  4007. ++}
  4008. ++
  4009. ++char **tempvar_list;
  4010. ++int tvlist_ind;
  4011. ++
  4012. ++/* Push the variable described by (SHELL_VAR *)DATA down to the next
  4013. ++   variable context from the temporary environment. */
  4014. ++static void
  4015. ++push_temp_var (data)
  4016. ++     PTR_T data;
  4017. ++{
  4018. ++  SHELL_VAR *var, *v;
  4019. ++  HASH_TABLE *binding_table;
  4020. ++
  4021. ++  var = (SHELL_VAR *)data;
  4022. ++
  4023. ++  binding_table = shell_variables->table;
  4024. ++  if (binding_table == 0)
  4025. ++    {
  4026. ++      if (shell_variables == global_variables)
  4027. ++      /* shouldn't happen */
  4028. ++      binding_table = shell_variables->table = global_variables->table = hash_create (0);
  4029. ++      else
  4030. ++      binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
  4031. ++    }
  4032. ++
  4033. ++  v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
  4034. ++
  4035. ++  /* XXX - should we set the context here?  It shouldn't matter because of how
  4036. ++     assign_in_env works, but might want to check. */
  4037. ++  if (binding_table == global_variables->table)               /* XXX */
  4038. ++    var->attributes &= ~(att_tempvar|att_propagate);
  4039. ++  else
  4040. ++    {
  4041. ++      var->attributes |= att_propagate;
  4042. ++      if  (binding_table == shell_variables->table)
  4043. ++      shell_variables->flags |= VC_HASTMPVAR;
  4044. ++    }
  4045. ++  v->attributes |= var->attributes;
  4046. ++
  4047. ++  if (find_special_var (var->name) >= 0)
  4048. ++    tempvar_list[tvlist_ind++] = savestring (var->name);
  4049. ++
  4050. ++  dispose_variable (var);
  4051. ++}
  4052. ++
  4053. ++static void
  4054. ++propagate_temp_var (data)
  4055. ++     PTR_T data;
  4056. ++{
  4057. ++  SHELL_VAR *var;
  4058. ++
  4059. ++  var = (SHELL_VAR *)data;
  4060. ++  if (tempvar_p (var) && (var->attributes & att_propagate))
  4061. ++    push_temp_var (data);
  4062. ++  else
  4063. ++    {
  4064. ++      if (find_special_var (var->name) >= 0)
  4065. ++      tempvar_list[tvlist_ind++] = savestring (var->name);
  4066. ++      dispose_variable (var);
  4067. ++    }
  4068. ++}
  4069. ++
  4070. ++/* Free the storage used in the hash table for temporary
  4071. ++   environment variables.  PUSHF is a function to be called
  4072. ++   to free each hash table entry.  It takes care of pushing variables
  4073. ++   to previous scopes if appropriate.  PUSHF stores names of variables
  4074. ++   that require special handling (e.g., IFS) on tempvar_list, so this
  4075. ++   function can call stupidly_hack_special_variables on all the
  4076. ++   variables in the list when the temporary hash table is destroyed. */
  4077. ++static void
  4078. ++dispose_temporary_env (pushf)
  4079. ++     sh_free_func_t *pushf;
  4080. ++{
  4081. ++  int i;
  4082. ++
  4083. ++  tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
  4084. ++  tempvar_list[tvlist_ind = 0] = 0;
  4085. ++    
  4086. ++  hash_flush (temporary_env, pushf);
  4087. ++  hash_dispose (temporary_env);
  4088. ++  temporary_env = (HASH_TABLE *)NULL;
  4089. ++
  4090. ++  tempvar_list[tvlist_ind] = 0;
  4091. ++
  4092. ++  array_needs_making = 1;
  4093. ++
  4094. ++#if 0
  4095. ++  sv_ifs ("IFS");             /* XXX here for now -- check setifs in assign_in_env */  
  4096. ++#endif
  4097. ++  for (i = 0; i < tvlist_ind; i++)
  4098. ++    stupidly_hack_special_variables (tempvar_list[i]);
  4099. ++
  4100. ++  strvec_dispose (tempvar_list);
  4101. ++  tempvar_list = 0;
  4102. ++  tvlist_ind = 0;
  4103. ++}
  4104. ++
  4105. ++void
  4106. ++dispose_used_env_vars ()
  4107. ++{
  4108. ++  if (temporary_env)
  4109. ++    {
  4110. ++      dispose_temporary_env (propagate_temp_var);
  4111. ++      maybe_make_export_env ();
  4112. ++    }
  4113. ++}
  4114. ++
  4115. ++/* Take all of the shell variables in the temporary environment HASH_TABLE
  4116. ++   and make shell variables from them at the current variable context. */
  4117. ++void
  4118. ++merge_temporary_env ()
  4119. ++{
  4120. ++  if (temporary_env)
  4121. ++    dispose_temporary_env (push_temp_var);
  4122. ++}
  4123. ++
  4124. ++/* **************************************************************** */
  4125. ++/*                                                                */
  4126. ++/*         Creating and manipulating the environment              */
  4127. ++/*                                                                */
  4128. ++/* **************************************************************** */
  4129. ++
  4130. ++static inline char *
  4131. ++mk_env_string (name, value, isfunc)
  4132. ++     const char *name, *value;
  4133. ++     int isfunc;
  4134. ++{
  4135. ++  size_t name_len, value_len;
  4136. ++  char        *p, *q;
  4137. ++
  4138. ++  name_len = strlen (name);
  4139. ++  value_len = STRLEN (value);
  4140. ++
  4141. ++  /* If we are exporting a shell function, construct the encoded function
  4142. ++     name. */
  4143. ++  if (isfunc && value)
  4144. ++    {
  4145. ++      p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
  4146. ++      q = p;
  4147. ++      memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
  4148. ++      q += BASHFUNC_PREFLEN;
  4149. ++      memcpy (q, name, name_len);
  4150. ++      q += name_len;
  4151. ++      memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
  4152. ++      q += BASHFUNC_SUFFLEN;
  4153. ++    }
  4154. ++  else
  4155. ++    {
  4156. ++      p = (char *)xmalloc (2 + name_len + value_len);
  4157. ++      memcpy (p, name, name_len);
  4158. ++      q = p + name_len;
  4159. ++    }
  4160. ++
  4161. ++  q[0] = '=';
  4162. ++  if (value && *value)
  4163. ++    memcpy (q + 1, value, value_len + 1);
  4164. ++  else
  4165. ++    q[1] = '\0';
  4166. ++
  4167. ++  return (p);
  4168. ++}
  4169. ++
  4170. ++#ifdef DEBUG
  4171. ++/* Debugging */
  4172. ++static int
  4173. ++valid_exportstr (v)
  4174. ++     SHELL_VAR *v;
  4175. ++{
  4176. ++  char *s;
  4177. ++
  4178. ++  s = v->exportstr;
  4179. ++  if (s == 0)
  4180. ++    {
  4181. ++      internal_error (_("%s has null exportstr"), v->name);
  4182. ++      return (0);
  4183. ++    }
  4184. ++  if (legal_variable_starter ((unsigned char)*s) == 0)
  4185. ++    {
  4186. ++      internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
  4187. ++      return (0);
  4188. ++    }
  4189. ++  for (s = v->exportstr + 1; s && *s; s++)
  4190. ++    {
  4191. ++      if (*s == '=')
  4192. ++      break;
  4193. ++      if (legal_variable_char ((unsigned char)*s) == 0)
  4194. ++      {
  4195. ++        internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
  4196. ++        return (0);
  4197. ++      }
  4198. ++    }
  4199. ++  if (*s != '=')
  4200. ++    {
  4201. ++      internal_error (_("no `=' in exportstr for %s"), v->name);
  4202. ++      return (0);
  4203. ++    }
  4204. ++  return (1);
  4205. ++}
  4206. ++#endif
  4207. ++
  4208. ++static char **
  4209. ++make_env_array_from_var_list (vars)
  4210. ++     SHELL_VAR **vars;
  4211. ++{
  4212. ++  register int i, list_index;
  4213. ++  register SHELL_VAR *var;
  4214. ++  char **list, *value;
  4215. ++
  4216. ++  list = strvec_create ((1 + strvec_len ((char **)vars)));
  4217. ++
  4218. ++#define USE_EXPORTSTR (value == var->exportstr)
  4219. ++
  4220. ++  for (i = 0, list_index = 0; var = vars[i]; i++)
  4221. ++    {
  4222. ++#if defined (__CYGWIN__)
  4223. ++      /* We don't use the exportstr stuff on Cygwin at all. */
  4224. ++      INVALIDATE_EXPORTSTR (var);
  4225. ++#endif
  4226. ++      if (var->exportstr)
  4227. ++      value = var->exportstr;
  4228. ++      else if (function_p (var))
  4229. ++      value = named_function_string ((char *)NULL, function_cell (var), 0);
  4230. ++#if defined (ARRAY_VARS)
  4231. ++      else if (array_p (var))
  4232. ++#  if ARRAY_EXPORT
  4233. ++      value = array_to_assignment_string (array_cell (var));
  4234. ++#  else
  4235. ++      continue;       /* XXX array vars cannot yet be exported */
  4236. ++#  endif /* ARRAY_EXPORT */
  4237. ++      else if (assoc_p (var))
  4238. ++#  if 0
  4239. ++      value = assoc_to_assignment_string (assoc_cell (var));
  4240. ++#  else
  4241. ++      continue;       /* XXX associative array vars cannot yet be exported */
  4242. ++#  endif
  4243. ++#endif
  4244. ++      else
  4245. ++      value = value_cell (var);
  4246. ++
  4247. ++      if (value)
  4248. ++      {
  4249. ++        /* Gee, I'd like to get away with not using savestring() if we're
  4250. ++           using the cached exportstr... */
  4251. ++        list[list_index] = USE_EXPORTSTR ? savestring (value)
  4252. ++                                         : mk_env_string (var->name, value, function_p (var));
  4253. ++
  4254. ++        if (USE_EXPORTSTR == 0)
  4255. ++          SAVE_EXPORTSTR (var, list[list_index]);
  4256. ++
  4257. ++        list_index++;
  4258. ++#undef USE_EXPORTSTR
  4259. ++
  4260. ++#if 0 /* not yet */
  4261. ++#if defined (ARRAY_VARS)
  4262. ++        if (array_p (var) || assoc_p (var))
  4263. ++          free (value);
  4264. ++#endif
  4265. ++#endif
  4266. ++      }
  4267. ++    }
  4268. ++
  4269. ++  list[list_index] = (char *)NULL;
  4270. ++  return (list);
  4271. ++}
  4272. ++
  4273. ++/* Make an array of assignment statements from the hash table
  4274. ++   HASHED_VARS which contains SHELL_VARs.  Only visible, exported
  4275. ++   variables are eligible. */
  4276. ++static char **
  4277. ++make_var_export_array (vcxt)
  4278. ++     VAR_CONTEXT *vcxt;
  4279. ++{
  4280. ++  char **list;
  4281. ++  SHELL_VAR **vars;
  4282. ++
  4283. ++#if 0
  4284. ++  vars = map_over (visible_and_exported, vcxt);
  4285. ++#else
  4286. ++  vars = map_over (export_environment_candidate, vcxt);
  4287. ++#endif
  4288. ++
  4289. ++  if (vars == 0)
  4290. ++    return (char **)NULL;
  4291. ++
  4292. ++  list = make_env_array_from_var_list (vars);
  4293. ++
  4294. ++  free (vars);
  4295. ++  return (list);
  4296. ++}
  4297. ++
  4298. ++static char **
  4299. ++make_func_export_array ()
  4300. ++{
  4301. ++  char **list;
  4302. ++  SHELL_VAR **vars;
  4303. ++
  4304. ++  vars = map_over_funcs (visible_and_exported);
  4305. ++  if (vars == 0)
  4306. ++    return (char **)NULL;
  4307. ++
  4308. ++  list = make_env_array_from_var_list (vars);
  4309. ++
  4310. ++  free (vars);
  4311. ++  return (list);
  4312. ++}
  4313. ++
  4314. ++/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
  4315. ++#define add_to_export_env(envstr,do_alloc) \
  4316. ++do \
  4317. ++  { \
  4318. ++    if (export_env_index >= (export_env_size - 1)) \
  4319. ++      { \
  4320. ++      export_env_size += 16; \
  4321. ++      export_env = strvec_resize (export_env, export_env_size); \
  4322. ++      environ = export_env; \
  4323. ++      } \
  4324. ++    export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
  4325. ++    export_env[export_env_index] = (char *)NULL; \
  4326. ++  } while (0)
  4327. ++
  4328. ++/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
  4329. ++   array with the same left-hand side.  Return the new EXPORT_ENV. */
  4330. ++char **
  4331. ++add_or_supercede_exported_var (assign, do_alloc)
  4332. ++     char *assign;
  4333. ++     int do_alloc;
  4334. ++{
  4335. ++  register int i;
  4336. ++  int equal_offset;
  4337. ++
  4338. ++  equal_offset = assignment (assign, 0);
  4339. ++  if (equal_offset == 0)
  4340. ++    return (export_env);
  4341. ++
  4342. ++  /* If this is a function, then only supersede the function definition.
  4343. ++     We do this by including the `=() {' in the comparison, like
  4344. ++     initialize_shell_variables does. */
  4345. ++  if (assign[equal_offset + 1] == '(' &&
  4346. ++     strncmp (assign + equal_offset + 2, ") {", 3) == 0)              /* } */
  4347. ++    equal_offset += 4;
  4348. ++
  4349. ++  for (i = 0; i < export_env_index; i++)
  4350. ++    {
  4351. ++      if (STREQN (assign, export_env[i], equal_offset + 1))
  4352. ++      {
  4353. ++        free (export_env[i]);
  4354. ++        export_env[i] = do_alloc ? savestring (assign) : assign;
  4355. ++        return (export_env);
  4356. ++      }
  4357. ++    }
  4358. ++  add_to_export_env (assign, do_alloc);
  4359. ++  return (export_env);
  4360. ++}
  4361. ++
  4362. ++static void
  4363. ++add_temp_array_to_env (temp_array, do_alloc, do_supercede)
  4364. ++     char **temp_array;
  4365. ++     int do_alloc, do_supercede;
  4366. ++{
  4367. ++  register int i;
  4368. ++
  4369. ++  if (temp_array == 0)
  4370. ++    return;
  4371. ++
  4372. ++  for (i = 0; temp_array[i]; i++)
  4373. ++    {
  4374. ++      if (do_supercede)
  4375. ++      export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
  4376. ++      else
  4377. ++      add_to_export_env (temp_array[i], do_alloc);
  4378. ++    }
  4379. ++
  4380. ++  free (temp_array);
  4381. ++}
  4382. ++
  4383. ++/* Make the environment array for the command about to be executed, if the
  4384. ++   array needs making.  Otherwise, do nothing.  If a shell action could
  4385. ++   change the array that commands receive for their environment, then the
  4386. ++   code should `array_needs_making++'.
  4387. ++
  4388. ++   The order to add to the array is:
  4389. ++      temporary_env
  4390. ++      list of var contexts whose head is shell_variables
  4391. ++      shell_functions
  4392. ++
  4393. ++  This is the shell variable lookup order.  We add only new variable
  4394. ++  names at each step, which allows local variables and variables in
  4395. ++  the temporary environments to shadow variables in the global (or
  4396. ++  any previous) scope.
  4397. ++*/
  4398. ++
  4399. ++static int
  4400. ++n_shell_variables ()
  4401. ++{
  4402. ++  VAR_CONTEXT *vc;
  4403. ++  int n;
  4404. ++
  4405. ++  for (n = 0, vc = shell_variables; vc; vc = vc->down)
  4406. ++    n += HASH_ENTRIES (vc->table);
  4407. ++  return n;
  4408. ++}
  4409. ++
  4410. ++int
  4411. ++chkexport (name)
  4412. ++     char *name;
  4413. ++{
  4414. ++  SHELL_VAR *v;
  4415. ++
  4416. ++  v = find_variable (name);
  4417. ++  if (v && exported_p (v))
  4418. ++    {
  4419. ++      array_needs_making = 1;
  4420. ++      maybe_make_export_env ();
  4421. ++      return 1;
  4422. ++    }
  4423. ++  return 0;
  4424. ++}
  4425. ++
  4426. ++void
  4427. ++maybe_make_export_env ()
  4428. ++{
  4429. ++  register char **temp_array;
  4430. ++  int new_size;
  4431. ++  VAR_CONTEXT *tcxt;
  4432. ++
  4433. ++  if (array_needs_making)
  4434. ++    {
  4435. ++      if (export_env)
  4436. ++      strvec_flush (export_env);
  4437. ++
  4438. ++      /* Make a guess based on how many shell variables and functions we
  4439. ++       have.  Since there will always be array variables, and array
  4440. ++       variables are not (yet) exported, this will always be big enough
  4441. ++       for the exported variables and functions. */
  4442. ++      new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
  4443. ++               HASH_ENTRIES (temporary_env);
  4444. ++      if (new_size > export_env_size)
  4445. ++      {
  4446. ++        export_env_size = new_size;
  4447. ++        export_env = strvec_resize (export_env, export_env_size);
  4448. ++        environ = export_env;
  4449. ++      }
  4450. ++      export_env[export_env_index = 0] = (char *)NULL;
  4451. ++
  4452. ++      /* Make a dummy variable context from the temporary_env, stick it on
  4453. ++       the front of shell_variables, call make_var_export_array on the
  4454. ++       whole thing to flatten it, and convert the list of SHELL_VAR *s
  4455. ++       to the form needed by the environment. */
  4456. ++      if (temporary_env)
  4457. ++      {
  4458. ++        tcxt = new_var_context ((char *)NULL, 0);
  4459. ++        tcxt->table = temporary_env;
  4460. ++        tcxt->down = shell_variables;
  4461. ++      }
  4462. ++      else
  4463. ++      tcxt = shell_variables;
  4464. ++      
  4465. ++      temp_array = make_var_export_array (tcxt);
  4466. ++      if (temp_array)
  4467. ++      add_temp_array_to_env (temp_array, 0, 0);
  4468. ++
  4469. ++      if (tcxt != shell_variables)
  4470. ++      free (tcxt);
  4471. ++
  4472. ++#if defined (RESTRICTED_SHELL)
  4473. ++      /* Restricted shells may not export shell functions. */
  4474. ++      temp_array = restricted ? (char **)0 : make_func_export_array ();
  4475. ++#else
  4476. ++      temp_array = make_func_export_array ();
  4477. ++#endif
  4478. ++      if (temp_array)
  4479. ++      add_temp_array_to_env (temp_array, 0, 0);
  4480. ++
  4481. ++      array_needs_making = 0;
  4482. ++    }
  4483. ++}
  4484. ++
  4485. ++/* This is an efficiency hack.  PWD and OLDPWD are auto-exported, so
  4486. ++   we will need to remake the exported environment every time we
  4487. ++   change directories.  `_' is always put into the environment for
  4488. ++   every external command, so without special treatment it will always
  4489. ++   cause the environment to be remade.
  4490. ++
  4491. ++   If there is no other reason to make the exported environment, we can
  4492. ++   just update the variables in place and mark the exported environment
  4493. ++   as no longer needing a remake. */
  4494. ++void
  4495. ++update_export_env_inplace (env_prefix, preflen, value)
  4496. ++     char *env_prefix;
  4497. ++     int preflen;
  4498. ++     char *value;
  4499. ++{
  4500. ++  char *evar;
  4501. ++
  4502. ++  evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
  4503. ++  strcpy (evar, env_prefix);
  4504. ++  if (value)
  4505. ++    strcpy (evar + preflen, value);
  4506. ++  export_env = add_or_supercede_exported_var (evar, 0);
  4507. ++}
  4508. ++
  4509. ++/* We always put _ in the environment as the name of this command. */
  4510. ++void
  4511. ++put_command_name_into_env (command_name)
  4512. ++     char *command_name;
  4513. ++{
  4514. ++  update_export_env_inplace ("_=", 2, command_name);
  4515. ++}
  4516. ++
  4517. ++/* **************************************************************** */
  4518. ++/*                                                                */
  4519. ++/*                  Managing variable contexts                    */
  4520. ++/*                                                                */
  4521. ++/* **************************************************************** */
  4522. ++
  4523. ++/* Allocate and return a new variable context with NAME and FLAGS.
  4524. ++   NAME can be NULL. */
  4525. ++
  4526. ++VAR_CONTEXT *
  4527. ++new_var_context (name, flags)
  4528. ++     char *name;
  4529. ++     int flags;
  4530. ++{
  4531. ++  VAR_CONTEXT *vc;
  4532. ++
  4533. ++  vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
  4534. ++  vc->name = name ? savestring (name) : (char *)NULL;
  4535. ++  vc->scope = variable_context;
  4536. ++  vc->flags = flags;
  4537. ++
  4538. ++  vc->up = vc->down = (VAR_CONTEXT *)NULL;
  4539. ++  vc->table = (HASH_TABLE *)NULL;
  4540. ++
  4541. ++  return vc;
  4542. ++}
  4543. ++
  4544. ++/* Free a variable context and its data, including the hash table.  Dispose
  4545. ++   all of the variables. */
  4546. ++void
  4547. ++dispose_var_context (vc)
  4548. ++     VAR_CONTEXT *vc;
  4549. ++{
  4550. ++  FREE (vc->name);
  4551. ++
  4552. ++  if (vc->table)
  4553. ++    {
  4554. ++      delete_all_variables (vc->table);
  4555. ++      hash_dispose (vc->table);
  4556. ++    }
  4557. ++
  4558. ++  free (vc);
  4559. ++}
  4560. ++
  4561. ++/* Set VAR's scope level to the current variable context. */
  4562. ++static int
  4563. ++set_context (var)
  4564. ++     SHELL_VAR *var;
  4565. ++{
  4566. ++  return (var->context = variable_context);
  4567. ++}
  4568. ++
  4569. ++/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
  4570. ++   temporary variables, and push it onto shell_variables.  This is
  4571. ++   for shell functions. */
  4572. ++VAR_CONTEXT *
  4573. ++push_var_context (name, flags, tempvars)
  4574. ++     char *name;
  4575. ++     int flags;
  4576. ++     HASH_TABLE *tempvars;
  4577. ++{
  4578. ++  VAR_CONTEXT *vc;
  4579. ++
  4580. ++  vc = new_var_context (name, flags);
  4581. ++  vc->table = tempvars;
  4582. ++  if (tempvars)
  4583. ++    {
  4584. ++      /* Have to do this because the temp environment was created before
  4585. ++       variable_context was incremented. */
  4586. ++      flatten (tempvars, set_context, (VARLIST *)NULL, 0);
  4587. ++      vc->flags |= VC_HASTMPVAR;
  4588. ++    }
  4589. ++  vc->down = shell_variables;
  4590. ++  shell_variables->up = vc;
  4591. ++
  4592. ++  return (shell_variables = vc);
  4593. ++}
  4594. ++
  4595. ++static void
  4596. ++push_func_var (data)
  4597. ++     PTR_T data;
  4598. ++{
  4599. ++  SHELL_VAR *var, *v;
  4600. ++
  4601. ++  var = (SHELL_VAR *)data;
  4602. ++
  4603. ++  if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
  4604. ++    {
  4605. ++      /* Make sure we have a hash table to store the variable in while it is
  4606. ++       being propagated down to the global variables table.  Create one if
  4607. ++       we have to */
  4608. ++      if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
  4609. ++      shell_variables->table = hash_create (0);
  4610. ++      /* XXX - should we set v->context here? */
  4611. ++      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
  4612. ++      if (shell_variables == global_variables)
  4613. ++      var->attributes &= ~(att_tempvar|att_propagate);
  4614. ++      else
  4615. ++      shell_variables->flags |= VC_HASTMPVAR;
  4616. ++      v->attributes |= var->attributes;
  4617. ++    }
  4618. ++  else
  4619. ++    stupidly_hack_special_variables (var->name);      /* XXX */
  4620. ++
  4621. ++  dispose_variable (var);
  4622. ++}
  4623. ++
  4624. ++/* Pop the top context off of VCXT and dispose of it, returning the rest of
  4625. ++   the stack. */
  4626. ++void
  4627. ++pop_var_context ()
  4628. ++{
  4629. ++  VAR_CONTEXT *ret, *vcxt;
  4630. ++
  4631. ++  vcxt = shell_variables;
  4632. ++  if (vc_isfuncenv (vcxt) == 0)
  4633. ++    {
  4634. ++      internal_error (_("pop_var_context: head of shell_variables not a function context"));
  4635. ++      return;
  4636. ++    }
  4637. ++
  4638. ++  if (ret = vcxt->down)
  4639. ++    {
  4640. ++      ret->up = (VAR_CONTEXT *)NULL;
  4641. ++      shell_variables = ret;
  4642. ++      if (vcxt->table)
  4643. ++      hash_flush (vcxt->table, push_func_var);
  4644. ++      dispose_var_context (vcxt);
  4645. ++    }
  4646. ++  else
  4647. ++    internal_error (_("pop_var_context: no global_variables context"));
  4648. ++}
  4649. ++
  4650. ++/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
  4651. ++   all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
  4652. ++void
  4653. ++delete_all_contexts (vcxt)
  4654. ++     VAR_CONTEXT *vcxt;
  4655. ++{
  4656. ++  VAR_CONTEXT *v, *t;
  4657. ++
  4658. ++  for (v = vcxt; v != global_variables; v = t)
  4659. ++    {
  4660. ++      t = v->down;
  4661. ++      dispose_var_context (v);
  4662. ++    }    
  4663. ++
  4664. ++  delete_all_variables (global_variables->table);
  4665. ++  shell_variables = global_variables;
  4666. ++}
  4667. ++
  4668. ++/* **************************************************************** */
  4669. ++/*                                                                */
  4670. ++/*       Pushing and Popping temporary variable scopes            */
  4671. ++/*                                                                */
  4672. ++/* **************************************************************** */
  4673. ++
  4674. ++VAR_CONTEXT *
  4675. ++push_scope (flags, tmpvars)
  4676. ++     int flags;
  4677. ++     HASH_TABLE *tmpvars;
  4678. ++{
  4679. ++  return (push_var_context ((char *)NULL, flags, tmpvars));
  4680. ++}
  4681. ++
  4682. ++static void
  4683. ++push_exported_var (data)
  4684. ++     PTR_T data;
  4685. ++{
  4686. ++  SHELL_VAR *var, *v;
  4687. ++
  4688. ++  var = (SHELL_VAR *)data;
  4689. ++
  4690. ++  /* If a temp var had its export attribute set, or it's marked to be
  4691. ++     propagated, bind it in the previous scope before disposing it. */
  4692. ++  /* XXX - This isn't exactly right, because all tempenv variables have the
  4693. ++    export attribute set. */
  4694. ++#if 0
  4695. ++  if (exported_p (var) || (var->attributes & att_propagate))
  4696. ++#else
  4697. ++  if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
  4698. ++#endif
  4699. ++    {
  4700. ++      var->attributes &= ~att_tempvar;                /* XXX */
  4701. ++      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
  4702. ++      if (shell_variables == global_variables)
  4703. ++      var->attributes &= ~att_propagate;
  4704. ++      v->attributes |= var->attributes;
  4705. ++    }
  4706. ++  else
  4707. ++    stupidly_hack_special_variables (var->name);      /* XXX */
  4708. ++
  4709. ++  dispose_variable (var);
  4710. ++}
  4711. ++
  4712. ++void
  4713. ++pop_scope (is_special)
  4714. ++     int is_special;
  4715. ++{
  4716. ++  VAR_CONTEXT *vcxt, *ret;
  4717. ++
  4718. ++  vcxt = shell_variables;
  4719. ++  if (vc_istempscope (vcxt) == 0)
  4720. ++    {
  4721. ++      internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
  4722. ++      return;
  4723. ++    }
  4724. ++
  4725. ++  ret = vcxt->down;
  4726. ++  if (ret)
  4727. ++    ret->up = (VAR_CONTEXT *)NULL;
  4728. ++
  4729. ++  shell_variables = ret;
  4730. ++
  4731. ++  /* Now we can take care of merging variables in VCXT into set of scopes
  4732. ++     whose head is RET (shell_variables). */
  4733. ++  FREE (vcxt->name);
  4734. ++  if (vcxt->table)
  4735. ++    {
  4736. ++      if (is_special)
  4737. ++      hash_flush (vcxt->table, push_func_var);
  4738. ++      else
  4739. ++      hash_flush (vcxt->table, push_exported_var);
  4740. ++      hash_dispose (vcxt->table);
  4741. ++    }
  4742. ++  free (vcxt);
  4743. ++
  4744. ++  sv_ifs ("IFS");     /* XXX here for now */
  4745. ++}
  4746. ++
  4747. ++/* **************************************************************** */
  4748. ++/*                                                                */
  4749. ++/*             Pushing and Popping function contexts              */
  4750. ++/*                                                                */
  4751. ++/* **************************************************************** */
  4752. ++
  4753. ++static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
  4754. ++static int dollar_arg_stack_slots;
  4755. ++static int dollar_arg_stack_index;
  4756. ++
  4757. ++/* XXX - we might want to consider pushing and popping the `getopts' state
  4758. ++   when we modify the positional parameters. */
  4759. ++void
  4760. ++push_context (name, is_subshell, tempvars)
  4761. ++     char *name;      /* function name */
  4762. ++     int is_subshell;
  4763. ++     HASH_TABLE *tempvars;
  4764. ++{
  4765. ++  if (is_subshell == 0)
  4766. ++    push_dollar_vars ();
  4767. ++  variable_context++;
  4768. ++  push_var_context (name, VC_FUNCENV, tempvars);
  4769. ++}
  4770. ++
  4771. ++/* Only called when subshell == 0, so we don't need to check, and can
  4772. ++   unconditionally pop the dollar vars off the stack. */
  4773. ++void
  4774. ++pop_context ()
  4775. ++{
  4776. ++  pop_dollar_vars ();
  4777. ++  variable_context--;
  4778. ++  pop_var_context ();
  4779. ++
  4780. ++  sv_ifs ("IFS");             /* XXX here for now */
  4781. ++}
  4782. ++
  4783. ++/* Save the existing positional parameters on a stack. */
  4784. ++void
  4785. ++push_dollar_vars ()
  4786. ++{
  4787. ++  if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
  4788. ++    {
  4789. ++      dollar_arg_stack = (WORD_LIST **)
  4790. ++      xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
  4791. ++                * sizeof (WORD_LIST *));
  4792. ++    }
  4793. ++  dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
  4794. ++  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  4795. ++}
  4796. ++
  4797. ++/* Restore the positional parameters from our stack. */
  4798. ++void
  4799. ++pop_dollar_vars ()
  4800. ++{
  4801. ++  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
  4802. ++    return;
  4803. ++
  4804. ++  remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
  4805. ++  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  4806. ++  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  4807. ++  set_dollar_vars_unchanged ();
  4808. ++}
  4809. ++
  4810. ++void
  4811. ++dispose_saved_dollar_vars ()
  4812. ++{
  4813. ++  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
  4814. ++    return;
  4815. ++
  4816. ++  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  4817. ++  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  4818. ++}
  4819. ++
  4820. ++/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
  4821. ++
  4822. ++void
  4823. ++push_args (list)
  4824. ++     WORD_LIST *list;
  4825. ++{
  4826. ++#if defined (ARRAY_VARS) && defined (DEBUGGER)
  4827. ++  SHELL_VAR *bash_argv_v, *bash_argc_v;
  4828. ++  ARRAY *bash_argv_a, *bash_argc_a;
  4829. ++  WORD_LIST *l;
  4830. ++  arrayind_t i;
  4831. ++  char *t;
  4832. ++
  4833. ++  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
  4834. ++  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
  4835. ++
  4836. ++  for (l = list, i = 0; l; l = l->next, i++)
  4837. ++    array_push (bash_argv_a, l->word->word);
  4838. ++
  4839. ++  t = itos (i);
  4840. ++  array_push (bash_argc_a, t);
  4841. ++  free (t);
  4842. ++#endif /* ARRAY_VARS && DEBUGGER */
  4843. ++}
  4844. ++
  4845. ++/* Remove arguments from BASH_ARGV array.  Pop top element off BASH_ARGC
  4846. ++   array and use that value as the count of elements to remove from
  4847. ++   BASH_ARGV. */
  4848. ++void
  4849. ++pop_args ()
  4850. ++{
  4851. ++#if defined (ARRAY_VARS) && defined (DEBUGGER)
  4852. ++  SHELL_VAR *bash_argv_v, *bash_argc_v;
  4853. ++  ARRAY *bash_argv_a, *bash_argc_a;
  4854. ++  ARRAY_ELEMENT *ce;
  4855. ++  intmax_t i;
  4856. ++
  4857. ++  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
  4858. ++  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
  4859. ++
  4860. ++  ce = array_shift (bash_argc_a, 1, 0);
  4861. ++  if (ce == 0 || legal_number (element_value (ce), &i) == 0)
  4862. ++    i = 0;
  4863. ++
  4864. ++  for ( ; i > 0; i--)
  4865. ++    array_pop (bash_argv_a);
  4866. ++  array_dispose_element (ce);
  4867. ++#endif /* ARRAY_VARS && DEBUGGER */
  4868. ++}
  4869. ++
  4870. ++/*************************************************
  4871. ++ *                                             *
  4872. ++ *    Functions to manage special variables    *
  4873. ++ *                                             *
  4874. ++ *************************************************/
  4875. ++
  4876. ++/* Extern declarations for variables this code has to manage. */
  4877. ++extern int eof_encountered, eof_encountered_limit, ignoreeof;
  4878. ++
  4879. ++#if defined (READLINE)
  4880. ++extern int hostname_list_initialized;
  4881. ++#endif
  4882. ++
  4883. ++/* An alist of name.function for each special variable.  Most of the
  4884. ++   functions don't do much, and in fact, this would be faster with a
  4885. ++   switch statement, but by the end of this file, I am sick of switch
  4886. ++   statements. */
  4887. ++
  4888. ++#define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
  4889. ++
  4890. ++/* This table will be sorted with qsort() the first time it's accessed. */
  4891. ++struct name_and_function {
  4892. ++  char *name;
  4893. ++  sh_sv_func_t *function;
  4894. ++};
  4895. ++
  4896. ++static struct name_and_function special_vars[] = {
  4897. ++  { "BASH_COMPAT", sv_shcompat },
  4898. ++  { "BASH_XTRACEFD", sv_xtracefd },
  4899. ++
  4900. ++#if defined (JOB_CONTROL)
  4901. ++  { "CHILD_MAX", sv_childmax },
  4902. ++#endif
  4903. ++
  4904. ++#if defined (READLINE)
  4905. ++#  if defined (STRICT_POSIX)
  4906. ++  { "COLUMNS", sv_winsize },
  4907. ++#  endif
  4908. ++  { "COMP_WORDBREAKS", sv_comp_wordbreaks },
  4909. ++#endif
  4910. ++
  4911. ++  { "FUNCNEST", sv_funcnest },
  4912. ++
  4913. ++  { "GLOBIGNORE", sv_globignore },
  4914. ++
  4915. ++#if defined (HISTORY)
  4916. ++  { "HISTCONTROL", sv_history_control },
  4917. ++  { "HISTFILESIZE", sv_histsize },
  4918. ++  { "HISTIGNORE", sv_histignore },
  4919. ++  { "HISTSIZE", sv_histsize },
  4920. ++  { "HISTTIMEFORMAT", sv_histtimefmt },
  4921. ++#endif
  4922. ++
  4923. ++#if defined (__CYGWIN__)
  4924. ++  { "HOME", sv_home },
  4925. ++#endif
  4926. ++
  4927. ++#if defined (READLINE)
  4928. ++  { "HOSTFILE", sv_hostfile },
  4929. ++#endif
  4930. ++
  4931. ++  { "IFS", sv_ifs },
  4932. ++  { "IGNOREEOF", sv_ignoreeof },
  4933. ++
  4934. ++  { "LANG", sv_locale },
  4935. ++  { "LC_ALL", sv_locale },
  4936. ++  { "LC_COLLATE", sv_locale },
  4937. ++  { "LC_CTYPE", sv_locale },
  4938. ++  { "LC_MESSAGES", sv_locale },
  4939. ++  { "LC_NUMERIC", sv_locale },
  4940. ++  { "LC_TIME", sv_locale },
  4941. ++
  4942. ++#if defined (READLINE) && defined (STRICT_POSIX)
  4943. ++  { "LINES", sv_winsize },
  4944. ++#endif
  4945. ++
  4946. ++  { "MAIL", sv_mail },
  4947. ++  { "MAILCHECK", sv_mail },
  4948. ++  { "MAILPATH", sv_mail },
  4949. ++
  4950. ++  { "OPTERR", sv_opterr },
  4951. ++  { "OPTIND", sv_optind },
  4952. ++
  4953. ++  { "PATH", sv_path },
  4954. ++  { "POSIXLY_CORRECT", sv_strict_posix },
  4955. ++
  4956. ++#if defined (READLINE)
  4957. ++  { "TERM", sv_terminal },
  4958. ++  { "TERMCAP", sv_terminal },
  4959. ++  { "TERMINFO", sv_terminal },
  4960. ++#endif /* READLINE */
  4961. ++
  4962. ++  { "TEXTDOMAIN", sv_locale },
  4963. ++  { "TEXTDOMAINDIR", sv_locale },
  4964. ++
  4965. ++#if defined (HAVE_TZSET)
  4966. ++  { "TZ", sv_tz },
  4967. ++#endif
  4968. ++
  4969. ++#if defined (HISTORY) && defined (BANG_HISTORY)
  4970. ++  { "histchars", sv_histchars },
  4971. ++#endif /* HISTORY && BANG_HISTORY */
  4972. ++
  4973. ++  { "ignoreeof", sv_ignoreeof },
  4974. ++
  4975. ++  { (char *)0, (sh_sv_func_t *)0 }
  4976. ++};
  4977. ++
  4978. ++#define N_SPECIAL_VARS        (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
  4979. ++
  4980. ++static int
  4981. ++sv_compare (sv1, sv2)
  4982. ++     struct name_and_function *sv1, *sv2;
  4983. ++{
  4984. ++  int r;
  4985. ++
  4986. ++  if ((r = sv1->name[0] - sv2->name[0]) == 0)
  4987. ++    r = strcmp (sv1->name, sv2->name);
  4988. ++  return r;
  4989. ++}
  4990. ++
  4991. ++static inline int
  4992. ++find_special_var (name)
  4993. ++     const char *name;
  4994. ++{
  4995. ++  register int i, r;
  4996. ++
  4997. ++  for (i = 0; special_vars[i].name; i++)
  4998. ++    {
  4999. ++      r = special_vars[i].name[0] - name[0];
  5000. ++      if (r == 0)
  5001. ++      r = strcmp (special_vars[i].name, name);
  5002. ++      if (r == 0)
  5003. ++      return i;
  5004. ++      else if (r > 0)
  5005. ++      /* Can't match any of rest of elements in sorted list.  Take this out
  5006. ++         if it causes problems in certain environments. */
  5007. ++      break;
  5008. ++    }
  5009. ++  return -1;
  5010. ++}
  5011. ++
  5012. ++/* The variable in NAME has just had its state changed.  Check to see if it
  5013. ++   is one of the special ones where something special happens. */
  5014. ++void
  5015. ++stupidly_hack_special_variables (name)
  5016. ++     char *name;
  5017. ++{
  5018. ++  static int sv_sorted = 0;
  5019. ++  int i;
  5020. ++
  5021. ++  if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
  5022. ++    {
  5023. ++      qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
  5024. ++              (QSFUNC *)sv_compare);
  5025. ++      sv_sorted = 1;
  5026. ++    }
  5027. ++
  5028. ++  i = find_special_var (name);
  5029. ++  if (i != -1)
  5030. ++    (*(special_vars[i].function)) (name);
  5031. ++}
  5032. ++
  5033. ++/* Special variables that need hooks to be run when they are unset as part
  5034. ++   of shell reinitialization should have their sv_ functions run here. */
  5035. ++void
  5036. ++reinit_special_variables ()
  5037. ++{
  5038. ++#if defined (READLINE)
  5039. ++  sv_comp_wordbreaks ("COMP_WORDBREAKS");
  5040. ++#endif
  5041. ++  sv_globignore ("GLOBIGNORE");
  5042. ++  sv_opterr ("OPTERR");
  5043. ++}
  5044. ++
  5045. ++void
  5046. ++sv_ifs (name)
  5047. ++     char *name;
  5048. ++{
  5049. ++  SHELL_VAR *v;
  5050. ++
  5051. ++  v = find_variable ("IFS");
  5052. ++  setifs (v);
  5053. ++}
  5054. ++
  5055. ++/* What to do just after the PATH variable has changed. */
  5056. ++void
  5057. ++sv_path (name)
  5058. ++     char *name;
  5059. ++{
  5060. ++  /* hash -r */
  5061. ++  phash_flush ();
  5062. ++}
  5063. ++
  5064. ++/* What to do just after one of the MAILxxxx variables has changed.  NAME
  5065. ++   is the name of the variable.  This is called with NAME set to one of
  5066. ++   MAIL, MAILCHECK, or MAILPATH.  */
  5067. ++void
  5068. ++sv_mail (name)
  5069. ++     char *name;
  5070. ++{
  5071. ++  /* If the time interval for checking the files has changed, then
  5072. ++     reset the mail timer.  Otherwise, one of the pathname vars
  5073. ++     to the users mailbox has changed, so rebuild the array of
  5074. ++     filenames. */
  5075. ++  if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
  5076. ++    reset_mail_timer ();
  5077. ++  else
  5078. ++    {
  5079. ++      free_mail_files ();
  5080. ++      remember_mail_dates ();
  5081. ++    }
  5082. ++}
  5083. ++
  5084. ++void
  5085. ++sv_funcnest (name)
  5086. ++     char *name;
  5087. ++{
  5088. ++  SHELL_VAR *v;
  5089. ++  intmax_t num;
  5090. ++
  5091. ++  v = find_variable (name);
  5092. ++  if (v == 0)
  5093. ++    funcnest_max = 0;
  5094. ++  else if (legal_number (value_cell (v), &num) == 0)
  5095. ++    funcnest_max = 0;
  5096. ++  else
  5097. ++    funcnest_max = num;
  5098. ++}
  5099. ++
  5100. ++/* What to do when GLOBIGNORE changes. */
  5101. ++void
  5102. ++sv_globignore (name)
  5103. ++     char *name;
  5104. ++{
  5105. ++  if (privileged_mode == 0)
  5106. ++    setup_glob_ignore (name);
  5107. ++}
  5108. ++
  5109. ++#if defined (READLINE)
  5110. ++void
  5111. ++sv_comp_wordbreaks (name)
  5112. ++     char *name;
  5113. ++{
  5114. ++  SHELL_VAR *sv;
  5115. ++
  5116. ++  sv = find_variable (name);
  5117. ++  if (sv == 0)
  5118. ++    reset_completer_word_break_chars ();
  5119. ++}
  5120. ++
  5121. ++/* What to do just after one of the TERMxxx variables has changed.
  5122. ++   If we are an interactive shell, then try to reset the terminal
  5123. ++   information in readline. */
  5124. ++void
  5125. ++sv_terminal (name)
  5126. ++     char *name;
  5127. ++{
  5128. ++  if (interactive_shell && no_line_editing == 0)
  5129. ++    rl_reset_terminal (get_string_value ("TERM"));
  5130. ++}
  5131. ++
  5132. ++void
  5133. ++sv_hostfile (name)
  5134. ++     char *name;
  5135. ++{
  5136. ++  SHELL_VAR *v;
  5137. ++
  5138. ++  v = find_variable (name);
  5139. ++  if (v == 0)
  5140. ++    clear_hostname_list ();
  5141. ++  else
  5142. ++    hostname_list_initialized = 0;
  5143. ++}
  5144. ++
  5145. ++#if defined (STRICT_POSIX)
  5146. ++/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
  5147. ++   found in the initial environment) to override the terminal size reported by
  5148. ++   the kernel. */
  5149. ++void
  5150. ++sv_winsize (name)
  5151. ++     char *name;
  5152. ++{
  5153. ++  SHELL_VAR *v;
  5154. ++  intmax_t xd;
  5155. ++  int d;
  5156. ++
  5157. ++  if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
  5158. ++    return;
  5159. ++
  5160. ++  v = find_variable (name);
  5161. ++  if (v == 0 || var_isnull (v))
  5162. ++    rl_reset_screen_size ();
  5163. ++  else
  5164. ++    {
  5165. ++      if (legal_number (value_cell (v), &xd) == 0)
  5166. ++      return;
  5167. ++      winsize_assignment = 1;
  5168. ++      d = xd;                 /* truncate */
  5169. ++      if (name[0] == 'L')     /* LINES */
  5170. ++      rl_set_screen_size (d, -1);
  5171. ++      else                    /* COLUMNS */
  5172. ++      rl_set_screen_size (-1, d);
  5173. ++      winsize_assignment = 0;
  5174. ++    }
  5175. ++}
  5176. ++#endif /* STRICT_POSIX */
  5177. ++#endif /* READLINE */
  5178. ++
  5179. ++/* Update the value of HOME in the export environment so tilde expansion will
  5180. ++   work on cygwin. */
  5181. ++#if defined (__CYGWIN__)
  5182. ++sv_home (name)
  5183. ++     char *name;
  5184. ++{
  5185. ++  array_needs_making = 1;
  5186. ++  maybe_make_export_env ();
  5187. ++}
  5188. ++#endif
  5189. ++
  5190. ++#if defined (HISTORY)
  5191. ++/* What to do after the HISTSIZE or HISTFILESIZE variables change.
  5192. ++   If there is a value for this HISTSIZE (and it is numeric), then stifle
  5193. ++   the history.  Otherwise, if there is NO value for this variable,
  5194. ++   unstifle the history.  If name is HISTFILESIZE, and its value is
  5195. ++   numeric, truncate the history file to hold no more than that many
  5196. ++   lines. */
  5197. ++void
  5198. ++sv_histsize (name)
  5199. ++     char *name;
  5200. ++{
  5201. ++  char *temp;
  5202. ++  intmax_t num;
  5203. ++  int hmax;
  5204. ++
  5205. ++  temp = get_string_value (name);
  5206. ++
  5207. ++  if (temp && *temp)
  5208. ++    {
  5209. ++      if (legal_number (temp, &num))
  5210. ++      {
  5211. ++        hmax = num;
  5212. ++        if (hmax < 0 && name[4] == 'S')
  5213. ++          unstifle_history ();        /* unstifle history if HISTSIZE < 0 */
  5214. ++        else if (name[4] == 'S')
  5215. ++          {
  5216. ++            stifle_history (hmax);
  5217. ++            hmax = where_history ();
  5218. ++            if (history_lines_this_session > hmax)
  5219. ++              history_lines_this_session = hmax;
  5220. ++          }
  5221. ++        else if (hmax >= 0)   /* truncate HISTFILE if HISTFILESIZE >= 0 */
  5222. ++          {
  5223. ++            history_truncate_file (get_string_value ("HISTFILE"), hmax);
  5224. ++            if (hmax <= history_lines_in_file)
  5225. ++              history_lines_in_file = hmax;
  5226. ++          }
  5227. ++      }
  5228. ++    }
  5229. ++  else if (name[4] == 'S')
  5230. ++    unstifle_history ();
  5231. ++}
  5232. ++
  5233. ++/* What to do after the HISTIGNORE variable changes. */
  5234. ++void
  5235. ++sv_histignore (name)
  5236. ++     char *name;
  5237. ++{
  5238. ++  setup_history_ignore (name);
  5239. ++}
  5240. ++
  5241. ++/* What to do after the HISTCONTROL variable changes. */
  5242. ++void
  5243. ++sv_history_control (name)
  5244. ++     char *name;
  5245. ++{
  5246. ++  char *temp;
  5247. ++  char *val;
  5248. ++  int tptr;
  5249. ++
  5250. ++  history_control = 0;
  5251. ++  temp = get_string_value (name);
  5252. ++
  5253. ++  if (temp == 0 || *temp == 0)
  5254. ++    return;
  5255. ++
  5256. ++  tptr = 0;
  5257. ++  while (val = extract_colon_unit (temp, &tptr))
  5258. ++    {
  5259. ++      if (STREQ (val, "ignorespace"))
  5260. ++      history_control |= HC_IGNSPACE;
  5261. ++      else if (STREQ (val, "ignoredups"))
  5262. ++      history_control |= HC_IGNDUPS;
  5263. ++      else if (STREQ (val, "ignoreboth"))
  5264. ++      history_control |= HC_IGNBOTH;
  5265. ++      else if (STREQ (val, "erasedups"))
  5266. ++      history_control |= HC_ERASEDUPS;
  5267. ++
  5268. ++      free (val);
  5269. ++    }
  5270. ++}
  5271. ++
  5272. ++#if defined (BANG_HISTORY)
  5273. ++/* Setting/unsetting of the history expansion character. */
  5274. ++void
  5275. ++sv_histchars (name)
  5276. ++     char *name;
  5277. ++{
  5278. ++  char *temp;
  5279. ++
  5280. ++  temp = get_string_value (name);
  5281. ++  if (temp)
  5282. ++    {
  5283. ++      history_expansion_char = *temp;
  5284. ++      if (temp[0] && temp[1])
  5285. ++      {
  5286. ++        history_subst_char = temp[1];
  5287. ++        if (temp[2])
  5288. ++            history_comment_char = temp[2];
  5289. ++      }
  5290. ++    }
  5291. ++  else
  5292. ++    {
  5293. ++      history_expansion_char = '!';
  5294. ++      history_subst_char = '^';
  5295. ++      history_comment_char = '#';
  5296. ++    }
  5297. ++}
  5298. ++#endif /* BANG_HISTORY */
  5299. ++
  5300. ++void
  5301. ++sv_histtimefmt (name)
  5302. ++     char *name;
  5303. ++{
  5304. ++  SHELL_VAR *v;
  5305. ++
  5306. ++  if (v = find_variable (name))
  5307. ++    {
  5308. ++      if (history_comment_char == 0)
  5309. ++      history_comment_char = '#';
  5310. ++    }
  5311. ++  history_write_timestamps = (v != 0);
  5312. ++}
  5313. ++#endif /* HISTORY */
  5314. ++
  5315. ++#if defined (HAVE_TZSET)
  5316. ++void
  5317. ++sv_tz (name)
  5318. ++     char *name;
  5319. ++{
  5320. ++  if (chkexport (name))
  5321. ++    tzset ();
  5322. ++}
  5323. ++#endif
  5324. ++
  5325. ++/* If the variable exists, then the value of it can be the number
  5326. ++   of times we actually ignore the EOF.  The default is small,
  5327. ++   (smaller than csh, anyway). */
  5328. ++void
  5329. ++sv_ignoreeof (name)
  5330. ++     char *name;
  5331. ++{
  5332. ++  SHELL_VAR *tmp_var;
  5333. ++  char *temp;
  5334. ++
  5335. ++  eof_encountered = 0;
  5336. ++
  5337. ++  tmp_var = find_variable (name);
  5338. ++  ignoreeof = tmp_var != 0;
  5339. ++  temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
  5340. ++  if (temp)
  5341. ++    eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
  5342. ++  set_shellopts ();   /* make sure `ignoreeof' is/is not in $SHELLOPTS */
  5343. ++}
  5344. ++
  5345. ++void
  5346. ++sv_optind (name)
  5347. ++     char *name;
  5348. ++{
  5349. ++  char *tt;
  5350. ++  int s;
  5351. ++
  5352. ++  tt = get_string_value ("OPTIND");
  5353. ++  if (tt && *tt)
  5354. ++    {
  5355. ++      s = atoi (tt);
  5356. ++
  5357. ++      /* According to POSIX, setting OPTIND=1 resets the internal state
  5358. ++       of getopt (). */
  5359. ++      if (s < 0 || s == 1)
  5360. ++      s = 0;
  5361. ++    }
  5362. ++  else
  5363. ++    s = 0;
  5364. ++  getopts_reset (s);
  5365. ++}
  5366. ++
  5367. ++void
  5368. ++sv_opterr (name)
  5369. ++     char *name;
  5370. ++{
  5371. ++  char *tt;
  5372. ++
  5373. ++  tt = get_string_value ("OPTERR");
  5374. ++  sh_opterr = (tt && *tt) ? atoi (tt) : 1;
  5375. ++}
  5376. ++
  5377. ++void
  5378. ++sv_strict_posix (name)
  5379. ++     char *name;
  5380. ++{
  5381. ++  SET_INT_VAR (name, posixly_correct);
  5382. ++  posix_initialize (posixly_correct);
  5383. ++#if defined (READLINE)
  5384. ++  if (interactive_shell)
  5385. ++    posix_readline_initialize (posixly_correct);
  5386. ++#endif /* READLINE */
  5387. ++  set_shellopts ();   /* make sure `posix' is/is not in $SHELLOPTS */
  5388. ++}
  5389. ++
  5390. ++void
  5391. ++sv_locale (name)
  5392. ++     char *name;
  5393. ++{
  5394. ++  char *v;
  5395. ++  int r;
  5396. ++
  5397. ++  v = get_string_value (name);
  5398. ++  if (name[0] == 'L' && name[1] == 'A')       /* LANG */
  5399. ++    r = set_lang (name, v);
  5400. ++  else
  5401. ++    r = set_locale_var (name, v);             /* LC_*, TEXTDOMAIN* */
  5402. ++
  5403. ++#if 1
  5404. ++  if (r == 0 && posixly_correct)
  5405. ++    last_command_exit_value = 1;
  5406. ++#endif
  5407. ++}
  5408. ++
  5409. ++#if defined (ARRAY_VARS)
  5410. ++void
  5411. ++set_pipestatus_array (ps, nproc)
  5412. ++     int *ps;
  5413. ++     int nproc;
  5414. ++{
  5415. ++  SHELL_VAR *v;
  5416. ++  ARRAY *a;
  5417. ++  ARRAY_ELEMENT *ae;
  5418. ++  register int i;
  5419. ++  char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
  5420. ++
  5421. ++  v = find_variable ("PIPESTATUS");
  5422. ++  if (v == 0)
  5423. ++    v = make_new_array_variable ("PIPESTATUS");
  5424. ++  if (array_p (v) == 0)
  5425. ++    return;           /* Do nothing if not an array variable. */
  5426. ++  a = array_cell (v);
  5427. ++
  5428. ++  if (a == 0 || array_num_elements (a) == 0)
  5429. ++    {
  5430. ++      for (i = 0; i < nproc; i++)     /* was ps[i] != -1, not i < nproc */
  5431. ++      {
  5432. ++        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  5433. ++        array_insert (a, i, t);
  5434. ++      }
  5435. ++      return;
  5436. ++    }
  5437. ++
  5438. ++  /* Fast case */
  5439. ++  if (array_num_elements (a) == nproc && nproc == 1)
  5440. ++    {
  5441. ++      ae = element_forw (a->head);
  5442. ++      free (element_value (ae));
  5443. ++      ae->value = itos (ps[0]);
  5444. ++    }
  5445. ++  else if (array_num_elements (a) <= nproc)
  5446. ++    {
  5447. ++      /* modify in array_num_elements members in place, then add */
  5448. ++      ae = a->head;
  5449. ++      for (i = 0; i < array_num_elements (a); i++)
  5450. ++      {
  5451. ++        ae = element_forw (ae);
  5452. ++        free (element_value (ae));
  5453. ++        ae->value = itos (ps[i]);
  5454. ++      }
  5455. ++      /* add any more */
  5456. ++      for ( ; i < nproc; i++)
  5457. ++      {
  5458. ++        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  5459. ++        array_insert (a, i, t);
  5460. ++      }
  5461. ++    }
  5462. ++  else
  5463. ++    {
  5464. ++      /* deleting elements.  it's faster to rebuild the array. */      
  5465. ++      array_flush (a);
  5466. ++      for (i = 0; ps[i] != -1; i++)
  5467. ++      {
  5468. ++        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  5469. ++        array_insert (a, i, t);
  5470. ++      }
  5471. ++    }
  5472. ++}
  5473. ++
  5474. ++ARRAY *
  5475. ++save_pipestatus_array ()
  5476. ++{
  5477. ++  SHELL_VAR *v;
  5478. ++  ARRAY *a, *a2;
  5479. ++
  5480. ++  v = find_variable ("PIPESTATUS");
  5481. ++  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
  5482. ++    return ((ARRAY *)NULL);
  5483. ++    
  5484. ++  a = array_cell (v);
  5485. ++  a2 = array_copy (array_cell (v));
  5486. ++
  5487. ++  return a2;
  5488. ++}
  5489. ++
  5490. ++void
  5491. ++restore_pipestatus_array (a)
  5492. ++     ARRAY *a;
  5493. ++{
  5494. ++  SHELL_VAR *v;
  5495. ++  ARRAY *a2;
  5496. ++
  5497. ++  v = find_variable ("PIPESTATUS");
  5498. ++  /* XXX - should we still assign even if existing value is NULL? */
  5499. ++  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
  5500. ++    return;
  5501. ++
  5502. ++  a2 = array_cell (v);
  5503. ++  var_setarray (v, a);
  5504. ++
  5505. ++  array_dispose (a2);
  5506. ++}
  5507. ++#endif
  5508. ++
  5509. ++void
  5510. ++set_pipestatus_from_exit (s)
  5511. ++     int s;
  5512. ++{
  5513. ++#if defined (ARRAY_VARS)
  5514. ++  static int v[2] = { 0, -1 };
  5515. ++
  5516. ++  v[0] = s;
  5517. ++  set_pipestatus_array (v, 1);
  5518. ++#endif
  5519. ++}
  5520. ++
  5521. ++void
  5522. ++sv_xtracefd (name)
  5523. ++     char *name;
  5524. ++{
  5525. ++  SHELL_VAR *v;
  5526. ++  char *t, *e;
  5527. ++  int fd;
  5528. ++  FILE *fp;
  5529. ++
  5530. ++  v = find_variable (name);
  5531. ++  if (v == 0)
  5532. ++    {
  5533. ++      xtrace_reset ();
  5534. ++      return;
  5535. ++    }
  5536. ++
  5537. ++  t = value_cell (v);
  5538. ++  if (t == 0 || *t == 0)
  5539. ++    xtrace_reset ();
  5540. ++  else
  5541. ++    {
  5542. ++      fd = (int)strtol (t, &e, 10);
  5543. ++      if (e != t && *e == '\0' && sh_validfd (fd))
  5544. ++      {
  5545. ++        fp = fdopen (fd, "w");
  5546. ++        if (fp == 0)
  5547. ++          internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
  5548. ++        else
  5549. ++          xtrace_set (fd, fp);
  5550. ++      }
  5551. ++      else
  5552. ++      internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
  5553. ++    }
  5554. ++}
  5555. ++
  5556. ++#define MIN_COMPAT_LEVEL 31
  5557. ++
  5558. ++void
  5559. ++sv_shcompat (name)
  5560. ++     char *name;
  5561. ++{
  5562. ++  SHELL_VAR *v;
  5563. ++  char *val;
  5564. ++  int tens, ones, compatval;
  5565. ++
  5566. ++  v = find_variable (name);
  5567. ++  if (v == 0)
  5568. ++    {
  5569. ++      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  5570. ++      set_compatibility_opts ();
  5571. ++      return;
  5572. ++    }
  5573. ++  val = value_cell (v);
  5574. ++  if (val == 0 || *val == '\0')
  5575. ++    {
  5576. ++      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  5577. ++      set_compatibility_opts ();
  5578. ++      return;
  5579. ++    }
  5580. ++  /* Handle decimal-like compatibility version specifications: 4.2 */
  5581. ++  if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
  5582. ++    {
  5583. ++      tens = val[0] - '0';
  5584. ++      ones = val[2] - '0';
  5585. ++      compatval = tens*10 + ones;
  5586. ++    }
  5587. ++  /* Handle integer-like compatibility version specifications: 42 */
  5588. ++  else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
  5589. ++    {
  5590. ++      tens = val[0] - '0';
  5591. ++      ones = val[1] - '0';
  5592. ++      compatval = tens*10 + ones;
  5593. ++    }
  5594. ++  else
  5595. ++    {
  5596. ++compat_error:
  5597. ++      internal_error (_("%s: %s: compatibility value out of range"), name, val);
  5598. ++      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  5599. ++      set_compatibility_opts ();
  5600. ++      return;
  5601. ++    }
  5602. ++
  5603. ++  if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
  5604. ++    goto compat_error;
  5605. ++
  5606. ++  shell_compatibility_level = compatval;
  5607. ++  set_compatibility_opts ();
  5608. ++}
  5609. ++
  5610. ++#if defined (JOB_CONTROL)
  5611. ++void
  5612. ++sv_childmax (name)
  5613. ++     char *name;
  5614. ++{
  5615. ++  char *tt;
  5616. ++  int s;
  5617. ++
  5618. ++  tt = get_string_value (name);
  5619. ++  s = (tt && *tt) ? atoi (tt) : 0;
  5620. ++  set_maxchild (s);
  5621. ++}
  5622. ++#endif
  5623. diff --git a/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch b/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
  5624. new file mode 100644
  5625. index 0000000..801b4a6
  5626. --- /dev/null
  5627. +++ b/ptxdist/patches/bash-4.3.30/0002-Bash-4.3-patch-32.patch
  5628. @@ -0,0 +1,5409 @@
  5629. +From: Chet Ramey <chet.ramey@case.edu>
  5630. +Date: Thu, 15 Jan 2015 10:20:45 -0500
  5631. +Subject: [PATCH] Bash-4.3 patch 32
  5632. +
  5633. +---
  5634. + jobs.c           |    4 +-
  5635. + patchlevel.h     |    2 +-
  5636. + variables.c.orig | 5365 ------------------------------------------------------
  5637. + 3 files changed, 4 insertions(+), 5367 deletions(-)
  5638. + delete mode 100644 variables.c.orig
  5639. +
  5640. +diff --git a/jobs.c b/jobs.c
  5641. +index f38b0c3f4446..b6e59eba0de8 100644
  5642. +--- a/jobs.c
  5643. ++++ b/jobs.c
  5644. +@@ -3339,7 +3339,9 @@ itrace("waitchld: waitpid returns %d block = %d", pid, block);
  5645. +       if (posixly_correct && this_shell_builtin && this_shell_builtin == wait_builtin)
  5646. +       {
  5647. +         interrupt_immediately = 0;
  5648. +-        trap_handler (SIGCHLD);       /* set pending_traps[SIGCHLD] */
  5649. ++        /* This was trap_handler (SIGCHLD) but that can lose traps if
  5650. ++           children_exited > 1 */
  5651. ++        queue_sigchld_trap (children_exited);
  5652. +         wait_signal_received = SIGCHLD;
  5653. +         /* If we're in a signal handler, let CHECK_WAIT_INTR pick it up;
  5654. +            run_pending_traps will call run_sigchld_trap later  */
  5655. +diff --git a/patchlevel.h b/patchlevel.h
  5656. +index 0ad46aafbdd9..b8bf38704ed2 100644
  5657. +--- a/patchlevel.h
  5658. ++++ b/patchlevel.h
  5659. +@@ -25,6 +25,6 @@
  5660. +    regexp `^#define[  ]*PATCHLEVEL', since that's what support/mkversion.sh
  5661. +    looks for to find the patch level (for the sccs version string). */
  5662. +
  5663. +-#define PATCHLEVEL 31
  5664. ++#define PATCHLEVEL 32
  5665. +
  5666. + #endif /* _PATCHLEVEL_H_ */
  5667. +diff --git a/variables.c.orig b/variables.c.orig
  5668. +deleted file mode 100644
  5669. +index 7c82710e0f0b..000000000000
  5670. +--- a/variables.c.orig
  5671. ++++ /dev/null
  5672. +@@ -1,5365 +0,0 @@
  5673. +-/* variables.c -- Functions for hacking shell variables. */
  5674. +-
  5675. +-/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
  5676. +-
  5677. +-   This file is part of GNU Bash, the Bourne Again SHell.
  5678. +-
  5679. +-   Bash is free software: you can redistribute it and/or modify
  5680. +-   it under the terms of the GNU General Public License as published by
  5681. +-   the Free Software Foundation, either version 3 of the License, or
  5682. +-   (at your option) any later version.
  5683. +-
  5684. +-   Bash is distributed in the hope that it will be useful,
  5685. +-   but WITHOUT ANY WARRANTY; without even the implied warranty of
  5686. +-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  5687. +-   GNU General Public License for more details.
  5688. +-
  5689. +-   You should have received a copy of the GNU General Public License
  5690. +-   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
  5691. +-*/
  5692. +-
  5693. +-#include "config.h"
  5694. +-
  5695. +-#include "bashtypes.h"
  5696. +-#include "posixstat.h"
  5697. +-#include "posixtime.h"
  5698. +-
  5699. +-#if defined (__QNX__)
  5700. +-#  if defined (__QNXNTO__)
  5701. +-#    include <sys/netmgr.h>
  5702. +-#  else
  5703. +-#    include <sys/vc.h>
  5704. +-#  endif /* !__QNXNTO__ */
  5705. +-#endif /* __QNX__ */
  5706. +-
  5707. +-#if defined (HAVE_UNISTD_H)
  5708. +-#  include <unistd.h>
  5709. +-#endif
  5710. +-
  5711. +-#include <stdio.h>
  5712. +-#include "chartypes.h"
  5713. +-#if defined (HAVE_PWD_H)
  5714. +-#  include <pwd.h>
  5715. +-#endif
  5716. +-#include "bashansi.h"
  5717. +-#include "bashintl.h"
  5718. +-
  5719. +-#define NEED_XTRACE_SET_DECL
  5720. +-
  5721. +-#include "shell.h"
  5722. +-#include "flags.h"
  5723. +-#include "execute_cmd.h"
  5724. +-#include "findcmd.h"
  5725. +-#include "mailcheck.h"
  5726. +-#include "input.h"
  5727. +-#include "hashcmd.h"
  5728. +-#include "pathexp.h"
  5729. +-#include "alias.h"
  5730. +-#include "jobs.h"
  5731. +-
  5732. +-#include "version.h"
  5733. +-
  5734. +-#include "builtins/getopt.h"
  5735. +-#include "builtins/common.h"
  5736. +-#include "builtins/builtext.h"
  5737. +-
  5738. +-#if defined (READLINE)
  5739. +-#  include "bashline.h"
  5740. +-#  include <readline/readline.h>
  5741. +-#else
  5742. +-#  include <tilde/tilde.h>
  5743. +-#endif
  5744. +-
  5745. +-#if defined (HISTORY)
  5746. +-#  include "bashhist.h"
  5747. +-#  include <readline/history.h>
  5748. +-#endif /* HISTORY */
  5749. +-
  5750. +-#if defined (PROGRAMMABLE_COMPLETION)
  5751. +-#  include "pcomplete.h"
  5752. +-#endif
  5753. +-
  5754. +-#define TEMPENV_HASH_BUCKETS  4       /* must be power of two */
  5755. +-
  5756. +-#define ifsname(s)    ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
  5757. +-
  5758. +-#define BASHFUNC_PREFIX               "BASH_FUNC_"
  5759. +-#define BASHFUNC_PREFLEN      10      /* == strlen(BASHFUNC_PREFIX */
  5760. +-#define BASHFUNC_SUFFIX               "%%"
  5761. +-#define BASHFUNC_SUFFLEN      2       /* == strlen(BASHFUNC_SUFFIX) */
  5762. +-
  5763. +-extern char **environ;
  5764. +-
  5765. +-/* Variables used here and defined in other files. */
  5766. +-extern int posixly_correct;
  5767. +-extern int line_number, line_number_base;
  5768. +-extern int subshell_environment, indirection_level, subshell_level;
  5769. +-extern int build_version, patch_level;
  5770. +-extern int expanding_redir;
  5771. +-extern int last_command_exit_value;
  5772. +-extern char *dist_version, *release_status;
  5773. +-extern char *shell_name;
  5774. +-extern char *primary_prompt, *secondary_prompt;
  5775. +-extern char *current_host_name;
  5776. +-extern sh_builtin_func_t *this_shell_builtin;
  5777. +-extern SHELL_VAR *this_shell_function;
  5778. +-extern char *the_printed_command_except_trap;
  5779. +-extern char *this_command_name;
  5780. +-extern char *command_execution_string;
  5781. +-extern time_t shell_start_time;
  5782. +-extern int assigning_in_environment;
  5783. +-extern int executing_builtin;
  5784. +-extern int funcnest_max;
  5785. +-
  5786. +-#if defined (READLINE)
  5787. +-extern int no_line_editing;
  5788. +-extern int perform_hostname_completion;
  5789. +-#endif
  5790. +-
  5791. +-/* The list of shell variables that the user has created at the global
  5792. +-   scope, or that came from the environment. */
  5793. +-VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
  5794. +-
  5795. +-/* The current list of shell variables, including function scopes */
  5796. +-VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
  5797. +-
  5798. +-/* The list of shell functions that the user has created, or that came from
  5799. +-   the environment. */
  5800. +-HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
  5801. +-
  5802. +-#if defined (DEBUGGER)
  5803. +-/* The table of shell function definitions that the user defined or that
  5804. +-   came from the environment. */
  5805. +-HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
  5806. +-#endif
  5807. +-
  5808. +-/* The current variable context.  This is really a count of how deep into
  5809. +-   executing functions we are. */
  5810. +-int variable_context = 0;
  5811. +-
  5812. +-/* The set of shell assignments which are made only in the environment
  5813. +-   for a single command. */
  5814. +-HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
  5815. +-
  5816. +-/* Set to non-zero if an assignment error occurs while putting variables
  5817. +-   into the temporary environment. */
  5818. +-int tempenv_assign_error;
  5819. +-
  5820. +-/* Some funky variables which are known about specially.  Here is where
  5821. +-   "$*", "$1", and all the cruft is kept. */
  5822. +-char *dollar_vars[10];
  5823. +-WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
  5824. +-
  5825. +-/* The value of $$. */
  5826. +-pid_t dollar_dollar_pid;
  5827. +-
  5828. +-/* Non-zero means that we have to remake EXPORT_ENV. */
  5829. +-int array_needs_making = 1;
  5830. +-
  5831. +-/* The number of times BASH has been executed.  This is set
  5832. +-   by initialize_variables (). */
  5833. +-int shell_level = 0;
  5834. +-
  5835. +-/* An array which is passed to commands as their environment.  It is
  5836. +-   manufactured from the union of the initial environment and the
  5837. +-   shell variables that are marked for export. */
  5838. +-char **export_env = (char **)NULL;
  5839. +-static int export_env_index;
  5840. +-static int export_env_size;
  5841. +-
  5842. +-#if defined (READLINE)
  5843. +-static int winsize_assignment;                /* currently assigning to LINES or COLUMNS */
  5844. +-#endif
  5845. +-
  5846. +-static HASH_TABLE *last_table_searched;       /* hash_lookup sets this */
  5847. +-
  5848. +-/* Some forward declarations. */
  5849. +-static void create_variable_tables __P((void));
  5850. +-
  5851. +-static void set_machine_vars __P((void));
  5852. +-static void set_home_var __P((void));
  5853. +-static void set_shell_var __P((void));
  5854. +-static char *get_bash_name __P((void));
  5855. +-static void initialize_shell_level __P((void));
  5856. +-static void uidset __P((void));
  5857. +-#if defined (ARRAY_VARS)
  5858. +-static void make_vers_array __P((void));
  5859. +-#endif
  5860. +-
  5861. +-static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
  5862. +-#if defined (ARRAY_VARS)
  5863. +-static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
  5864. +-#endif
  5865. +-static SHELL_VAR *get_self __P((SHELL_VAR *));
  5866. +-
  5867. +-#if defined (ARRAY_VARS)
  5868. +-static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
  5869. +-static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
  5870. +-#endif
  5871. +-
  5872. +-static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
  5873. +-static SHELL_VAR *get_seconds __P((SHELL_VAR *));
  5874. +-static SHELL_VAR *init_seconds_var __P((void));
  5875. +-
  5876. +-static int brand __P((void));
  5877. +-static void sbrand __P((unsigned long));              /* set bash random number generator. */
  5878. +-static void seedrand __P((void));                     /* seed generator randomly */
  5879. +-static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
  5880. +-static SHELL_VAR *get_random __P((SHELL_VAR *));
  5881. +-
  5882. +-static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
  5883. +-static SHELL_VAR *get_lineno __P((SHELL_VAR *));
  5884. +-
  5885. +-static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
  5886. +-static SHELL_VAR *get_subshell __P((SHELL_VAR *));
  5887. +-
  5888. +-static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
  5889. +-
  5890. +-#if defined (HISTORY)
  5891. +-static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
  5892. +-#endif
  5893. +-
  5894. +-#if defined (READLINE)
  5895. +-static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
  5896. +-static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
  5897. +-#endif
  5898. +-
  5899. +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  5900. +-static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
  5901. +-static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
  5902. +-#endif
  5903. +-
  5904. +-#if defined (ARRAY_VARS)
  5905. +-static SHELL_VAR *get_groupset __P((SHELL_VAR *));
  5906. +-
  5907. +-static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
  5908. +-static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
  5909. +-static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *,  char *, arrayind_t, char *));
  5910. +-#  if defined (ALIAS)
  5911. +-static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
  5912. +-static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
  5913. +-static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *,  char *, arrayind_t, char *));
  5914. +-#  endif
  5915. +-#endif
  5916. +-
  5917. +-static SHELL_VAR *get_funcname __P((SHELL_VAR *));
  5918. +-static SHELL_VAR *init_funcname_var __P((void));
  5919. +-
  5920. +-static void initialize_dynamic_variables __P((void));
  5921. +-
  5922. +-static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
  5923. +-static SHELL_VAR *new_shell_variable __P((const char *));
  5924. +-static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
  5925. +-static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
  5926. +-
  5927. +-static void dispose_variable_value __P((SHELL_VAR *));
  5928. +-static void free_variable_hash_data __P((PTR_T));
  5929. +-
  5930. +-static VARLIST *vlist_alloc __P((int));
  5931. +-static VARLIST *vlist_realloc __P((VARLIST *, int));
  5932. +-static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
  5933. +-
  5934. +-static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
  5935. +-
  5936. +-static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
  5937. +-
  5938. +-static SHELL_VAR **vapply __P((sh_var_map_func_t *));
  5939. +-static SHELL_VAR **fapply __P((sh_var_map_func_t *));
  5940. +-
  5941. +-static int visible_var __P((SHELL_VAR *));
  5942. +-static int visible_and_exported __P((SHELL_VAR *));
  5943. +-static int export_environment_candidate __P((SHELL_VAR *));
  5944. +-static int local_and_exported __P((SHELL_VAR *));
  5945. +-static int variable_in_context __P((SHELL_VAR *));
  5946. +-#if defined (ARRAY_VARS)
  5947. +-static int visible_array_vars __P((SHELL_VAR *));
  5948. +-#endif
  5949. +-
  5950. +-static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
  5951. +-static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
  5952. +-static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
  5953. +-
  5954. +-static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
  5955. +-static void push_temp_var __P((PTR_T));
  5956. +-static void propagate_temp_var __P((PTR_T));
  5957. +-static void dispose_temporary_env __P((sh_free_func_t *));    
  5958. +-
  5959. +-static inline char *mk_env_string __P((const char *, const char *, int));
  5960. +-static char **make_env_array_from_var_list __P((SHELL_VAR **));
  5961. +-static char **make_var_export_array __P((VAR_CONTEXT *));
  5962. +-static char **make_func_export_array __P((void));
  5963. +-static void add_temp_array_to_env __P((char **, int, int));
  5964. +-
  5965. +-static int n_shell_variables __P((void));
  5966. +-static int set_context __P((SHELL_VAR *));
  5967. +-
  5968. +-static void push_func_var __P((PTR_T));
  5969. +-static void push_exported_var __P((PTR_T));
  5970. +-
  5971. +-static inline int find_special_var __P((const char *));
  5972. +-
  5973. +-static void
  5974. +-create_variable_tables ()
  5975. +-{
  5976. +-  if (shell_variables == 0)
  5977. +-    {
  5978. +-      shell_variables = global_variables = new_var_context ((char *)NULL, 0);
  5979. +-      shell_variables->scope = 0;
  5980. +-      shell_variables->table = hash_create (0);
  5981. +-    }
  5982. +-
  5983. +-  if (shell_functions == 0)
  5984. +-    shell_functions = hash_create (0);
  5985. +-
  5986. +-#if defined (DEBUGGER)
  5987. +-  if (shell_function_defs == 0)
  5988. +-    shell_function_defs = hash_create (0);
  5989. +-#endif
  5990. +-}
  5991. +-
  5992. +-/* Initialize the shell variables from the current environment.
  5993. +-   If PRIVMODE is nonzero, don't import functions from ENV or
  5994. +-   parse $SHELLOPTS. */
  5995. +-void
  5996. +-initialize_shell_variables (env, privmode)
  5997. +-     char **env;
  5998. +-     int privmode;
  5999. +-{
  6000. +-  char *name, *string, *temp_string;
  6001. +-  int c, char_index, string_index, string_length, ro;
  6002. +-  SHELL_VAR *temp_var;
  6003. +-
  6004. +-  create_variable_tables ();
  6005. +-
  6006. +-  for (string_index = 0; string = env[string_index++]; )
  6007. +-    {
  6008. +-      char_index = 0;
  6009. +-      name = string;
  6010. +-      while ((c = *string++) && c != '=')
  6011. +-      ;
  6012. +-      if (string[-1] == '=')
  6013. +-      char_index = string - name - 1;
  6014. +-
  6015. +-      /* If there are weird things in the environment, like `=xxx' or a
  6016. +-       string without an `=', just skip them. */
  6017. +-      if (char_index == 0)
  6018. +-      continue;
  6019. +-
  6020. +-      /* ASSERT(name[char_index] == '=') */
  6021. +-      name[char_index] = '\0';
  6022. +-      /* Now, name = env variable name, string = env variable value, and
  6023. +-       char_index == strlen (name) */
  6024. +-
  6025. +-      temp_var = (SHELL_VAR *)NULL;
  6026. +-
  6027. +-      /* If exported function, define it now.  Don't import functions from
  6028. +-       the environment in privileged mode. */
  6029. +-      if (privmode == 0 && read_but_dont_execute == 0 &&
  6030. +-          STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
  6031. +-          STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
  6032. +-        STREQN ("() {", string, 4))
  6033. +-      {
  6034. +-        size_t namelen;
  6035. +-        char *tname;          /* desired imported function name */
  6036. +-
  6037. +-        namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
  6038. +-
  6039. +-        tname = name + BASHFUNC_PREFLEN;      /* start of func name */
  6040. +-        tname[namelen] = '\0';                /* now tname == func name */
  6041. +-
  6042. +-        string_length = strlen (string);
  6043. +-        temp_string = (char *)xmalloc (namelen + string_length + 2);
  6044. +-
  6045. +-        memcpy (temp_string, tname, namelen);
  6046. +-        temp_string[namelen] = ' ';
  6047. +-        memcpy (temp_string + namelen + 1, string, string_length + 1);
  6048. +-
  6049. +-        /* Don't import function names that are invalid identifiers from the
  6050. +-           environment, though we still allow them to be defined as shell
  6051. +-           variables. */
  6052. +-        if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
  6053. +-          parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
  6054. +-
  6055. +-        if (temp_var = find_function (tname))
  6056. +-          {
  6057. +-            VSETATTR (temp_var, (att_exported|att_imported));
  6058. +-            array_needs_making = 1;
  6059. +-          }
  6060. +-        else
  6061. +-          {
  6062. +-            if (temp_var = bind_variable (name, string, 0))
  6063. +-              {
  6064. +-                VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
  6065. +-                array_needs_making = 1;
  6066. +-              }
  6067. +-            last_command_exit_value = 1;
  6068. +-            report_error (_("error importing function definition for `%s'"), tname);
  6069. +-          }
  6070. +-
  6071. +-        /* Restore original suffix */
  6072. +-        tname[namelen] = BASHFUNC_SUFFIX[0];
  6073. +-      }
  6074. +-#if defined (ARRAY_VARS)
  6075. +-#  if ARRAY_EXPORT
  6076. +-      /* Array variables may not yet be exported. */
  6077. +-      else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
  6078. +-      {
  6079. +-        string_length = 1;
  6080. +-        temp_string = extract_array_assignment_list (string, &string_length);
  6081. +-        temp_var = assign_array_from_string (name, temp_string);
  6082. +-        FREE (temp_string);
  6083. +-        VSETATTR (temp_var, (att_exported | att_imported));
  6084. +-        array_needs_making = 1;
  6085. +-      }
  6086. +-#  endif /* ARRAY_EXPORT */
  6087. +-#endif
  6088. +-#if 0
  6089. +-      else if (legal_identifier (name))
  6090. +-#else
  6091. +-      else
  6092. +-#endif
  6093. +-      {
  6094. +-        ro = 0;
  6095. +-        if (posixly_correct && STREQ (name, "SHELLOPTS"))
  6096. +-          {
  6097. +-            temp_var = find_variable ("SHELLOPTS");
  6098. +-            ro = temp_var && readonly_p (temp_var);
  6099. +-            if (temp_var)
  6100. +-              VUNSETATTR (temp_var, att_readonly);
  6101. +-          }
  6102. +-        temp_var = bind_variable (name, string, 0);
  6103. +-        if (temp_var)
  6104. +-          {
  6105. +-            if (legal_identifier (name))
  6106. +-              VSETATTR (temp_var, (att_exported | att_imported));
  6107. +-            else
  6108. +-              VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
  6109. +-            if (ro)
  6110. +-              VSETATTR (temp_var, att_readonly);
  6111. +-            array_needs_making = 1;
  6112. +-          }
  6113. +-      }
  6114. +-
  6115. +-      name[char_index] = '=';
  6116. +-      /* temp_var can be NULL if it was an exported function with a syntax
  6117. +-       error (a different bug, but it still shouldn't dump core). */
  6118. +-      if (temp_var && function_p (temp_var) == 0)     /* XXX not yet */
  6119. +-      {
  6120. +-        CACHE_IMPORTSTR (temp_var, name);
  6121. +-      }
  6122. +-    }
  6123. +-
  6124. +-  set_pwd ();
  6125. +-
  6126. +-  /* Set up initial value of $_ */
  6127. +-  temp_var = set_if_not ("_", dollar_vars[0]);
  6128. +-
  6129. +-  /* Remember this pid. */
  6130. +-  dollar_dollar_pid = getpid ();
  6131. +-
  6132. +-  /* Now make our own defaults in case the vars that we think are
  6133. +-     important are missing. */
  6134. +-  temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
  6135. +-#if 0
  6136. +-  set_auto_export (temp_var); /* XXX */
  6137. +-#endif
  6138. +-
  6139. +-  temp_var = set_if_not ("TERM", "dumb");
  6140. +-#if 0
  6141. +-  set_auto_export (temp_var); /* XXX */
  6142. +-#endif
  6143. +-
  6144. +-#if defined (__QNX__)
  6145. +-  /* set node id -- don't import it from the environment */
  6146. +-  {
  6147. +-    char node_name[22];
  6148. +-#  if defined (__QNXNTO__)
  6149. +-    netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
  6150. +-#  else
  6151. +-    qnx_nidtostr (getnid (), node_name, sizeof (node_name));
  6152. +-#  endif
  6153. +-    temp_var = bind_variable ("NODE", node_name, 0);
  6154. +-    set_auto_export (temp_var);
  6155. +-  }
  6156. +-#endif
  6157. +-
  6158. +-  /* set up the prompts. */
  6159. +-  if (interactive_shell)
  6160. +-    {
  6161. +-#if defined (PROMPT_STRING_DECODE)
  6162. +-      set_if_not ("PS1", primary_prompt);
  6163. +-#else
  6164. +-      if (current_user.uid == -1)
  6165. +-      get_current_user_info ();
  6166. +-      set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
  6167. +-#endif
  6168. +-      set_if_not ("PS2", secondary_prompt);
  6169. +-    }
  6170. +-  set_if_not ("PS4", "+ ");
  6171. +-
  6172. +-  /* Don't allow IFS to be imported from the environment. */
  6173. +-  temp_var = bind_variable ("IFS", " \t\n", 0);
  6174. +-  setifs (temp_var);
  6175. +-
  6176. +-  /* Magic machine types.  Pretty convenient. */
  6177. +-  set_machine_vars ();
  6178. +-
  6179. +-  /* Default MAILCHECK for interactive shells.  Defer the creation of a
  6180. +-     default MAILPATH until the startup files are read, because MAIL
  6181. +-     names a mail file if MAILPATH is not set, and we should provide a
  6182. +-     default only if neither is set. */
  6183. +-  if (interactive_shell)
  6184. +-    {
  6185. +-      temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
  6186. +-      VSETATTR (temp_var, att_integer);
  6187. +-    }
  6188. +-
  6189. +-  /* Do some things with shell level. */
  6190. +-  initialize_shell_level ();
  6191. +-
  6192. +-  set_ppid ();
  6193. +-
  6194. +-  /* Initialize the `getopts' stuff. */
  6195. +-  temp_var = bind_variable ("OPTIND", "1", 0);
  6196. +-  VSETATTR (temp_var, att_integer);
  6197. +-  getopts_reset (0);
  6198. +-  bind_variable ("OPTERR", "1", 0);
  6199. +-  sh_opterr = 1;
  6200. +-
  6201. +-  if (login_shell == 1 && posixly_correct == 0)
  6202. +-    set_home_var ();
  6203. +-
  6204. +-  /* Get the full pathname to THIS shell, and set the BASH variable
  6205. +-     to it. */
  6206. +-  name = get_bash_name ();
  6207. +-  temp_var = bind_variable ("BASH", name, 0);
  6208. +-  free (name);
  6209. +-
  6210. +-  /* Make the exported environment variable SHELL be the user's login
  6211. +-     shell.  Note that the `tset' command looks at this variable
  6212. +-     to determine what style of commands to output; if it ends in "csh",
  6213. +-     then C-shell commands are output, else Bourne shell commands. */
  6214. +-  set_shell_var ();
  6215. +-
  6216. +-  /* Make a variable called BASH_VERSION which contains the version info. */
  6217. +-  bind_variable ("BASH_VERSION", shell_version_string (), 0);
  6218. +-#if defined (ARRAY_VARS)
  6219. +-  make_vers_array ();
  6220. +-#endif
  6221. +-
  6222. +-  if (command_execution_string)
  6223. +-    bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
  6224. +-
  6225. +-  /* Find out if we're supposed to be in Posix.2 mode via an
  6226. +-     environment variable. */
  6227. +-  temp_var = find_variable ("POSIXLY_CORRECT");
  6228. +-  if (!temp_var)
  6229. +-    temp_var = find_variable ("POSIX_PEDANTIC");
  6230. +-  if (temp_var && imported_p (temp_var))
  6231. +-    sv_strict_posix (temp_var->name);
  6232. +-
  6233. +-#if defined (HISTORY)
  6234. +-  /* Set history variables to defaults, and then do whatever we would
  6235. +-     do if the variable had just been set.  Do this only in the case
  6236. +-     that we are remembering commands on the history list. */
  6237. +-  if (remember_on_history)
  6238. +-    {
  6239. +-      name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
  6240. +-
  6241. +-      set_if_not ("HISTFILE", name);
  6242. +-      free (name);
  6243. +-    }
  6244. +-#endif /* HISTORY */
  6245. +-
  6246. +-  /* Seed the random number generator. */
  6247. +-  seedrand ();
  6248. +-
  6249. +-  /* Handle some "special" variables that we may have inherited from a
  6250. +-     parent shell. */
  6251. +-  if (interactive_shell)
  6252. +-    {
  6253. +-      temp_var = find_variable ("IGNOREEOF");
  6254. +-      if (!temp_var)
  6255. +-      temp_var = find_variable ("ignoreeof");
  6256. +-      if (temp_var && imported_p (temp_var))
  6257. +-      sv_ignoreeof (temp_var->name);
  6258. +-    }
  6259. +-
  6260. +-#if defined (HISTORY)
  6261. +-  if (interactive_shell && remember_on_history)
  6262. +-    {
  6263. +-      sv_history_control ("HISTCONTROL");
  6264. +-      sv_histignore ("HISTIGNORE");
  6265. +-      sv_histtimefmt ("HISTTIMEFORMAT");
  6266. +-    }
  6267. +-#endif /* HISTORY */
  6268. +-
  6269. +-#if defined (READLINE) && defined (STRICT_POSIX)
  6270. +-  /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
  6271. +-     -DSTRICT_POSIX */
  6272. +-  if (interactive_shell && posixly_correct && no_line_editing == 0)
  6273. +-    rl_prefer_env_winsize = 1;
  6274. +-#endif /* READLINE && STRICT_POSIX */
  6275. +-
  6276. +-     /*
  6277. +-      * 24 October 2001
  6278. +-      *
  6279. +-      * I'm tired of the arguing and bug reports.  Bash now leaves SSH_CLIENT
  6280. +-      * and SSH2_CLIENT alone.  I'm going to rely on the shell_level check in
  6281. +-      * isnetconn() to avoid running the startup files more often than wanted.
  6282. +-      * That will, of course, only work if the user's login shell is bash, so
  6283. +-      * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
  6284. +-      * in config-top.h.
  6285. +-      */
  6286. +-#if 0
  6287. +-  temp_var = find_variable ("SSH_CLIENT");
  6288. +-  if (temp_var && imported_p (temp_var))
  6289. +-    {
  6290. +-      VUNSETATTR (temp_var, att_exported);
  6291. +-      array_needs_making = 1;
  6292. +-    }
  6293. +-  temp_var = find_variable ("SSH2_CLIENT");
  6294. +-  if (temp_var && imported_p (temp_var))
  6295. +-    {
  6296. +-      VUNSETATTR (temp_var, att_exported);
  6297. +-      array_needs_making = 1;
  6298. +-    }
  6299. +-#endif
  6300. +-
  6301. +-  /* Get the user's real and effective user ids. */
  6302. +-  uidset ();
  6303. +-
  6304. +-  temp_var = find_variable ("BASH_XTRACEFD");
  6305. +-  if (temp_var && imported_p (temp_var))
  6306. +-    sv_xtracefd (temp_var->name);
  6307. +-
  6308. +-  /* Initialize the dynamic variables, and seed their values. */
  6309. +-  initialize_dynamic_variables ();
  6310. +-}
  6311. +-
  6312. +-/* **************************************************************** */
  6313. +-/*                                                                */
  6314. +-/*         Setting values for special shell variables             */
  6315. +-/*                                                                */
  6316. +-/* **************************************************************** */
  6317. +-
  6318. +-static void
  6319. +-set_machine_vars ()
  6320. +-{
  6321. +-  SHELL_VAR *temp_var;
  6322. +-
  6323. +-  temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
  6324. +-  temp_var = set_if_not ("OSTYPE", OSTYPE);
  6325. +-  temp_var = set_if_not ("MACHTYPE", MACHTYPE);
  6326. +-
  6327. +-  temp_var = set_if_not ("HOSTNAME", current_host_name);
  6328. +-}
  6329. +-
  6330. +-/* Set $HOME to the information in the password file if we didn't get
  6331. +-   it from the environment. */
  6332. +-
  6333. +-/* This function is not static so the tilde and readline libraries can
  6334. +-   use it. */
  6335. +-char *
  6336. +-sh_get_home_dir ()
  6337. +-{
  6338. +-  if (current_user.home_dir == 0)
  6339. +-    get_current_user_info ();
  6340. +-  return current_user.home_dir;
  6341. +-}
  6342. +-
  6343. +-static void
  6344. +-set_home_var ()
  6345. +-{
  6346. +-  SHELL_VAR *temp_var;
  6347. +-
  6348. +-  temp_var = find_variable ("HOME");
  6349. +-  if (temp_var == 0)
  6350. +-    temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
  6351. +-#if 0
  6352. +-  VSETATTR (temp_var, att_exported);
  6353. +-#endif
  6354. +-}
  6355. +-
  6356. +-/* Set $SHELL to the user's login shell if it is not already set.  Call
  6357. +-   get_current_user_info if we haven't already fetched the shell. */
  6358. +-static void
  6359. +-set_shell_var ()
  6360. +-{
  6361. +-  SHELL_VAR *temp_var;
  6362. +-
  6363. +-  temp_var = find_variable ("SHELL");
  6364. +-  if (temp_var == 0)
  6365. +-    {
  6366. +-      if (current_user.shell == 0)
  6367. +-      get_current_user_info ();
  6368. +-      temp_var = bind_variable ("SHELL", current_user.shell, 0);
  6369. +-    }
  6370. +-#if 0
  6371. +-  VSETATTR (temp_var, att_exported);
  6372. +-#endif
  6373. +-}
  6374. +-
  6375. +-static char *
  6376. +-get_bash_name ()
  6377. +-{
  6378. +-  char *name;
  6379. +-
  6380. +-  if ((login_shell == 1) && RELPATH(shell_name))
  6381. +-    {
  6382. +-      if (current_user.shell == 0)
  6383. +-      get_current_user_info ();
  6384. +-      name = savestring (current_user.shell);
  6385. +-    }
  6386. +-  else if (ABSPATH(shell_name))
  6387. +-    name = savestring (shell_name);
  6388. +-  else if (shell_name[0] == '.' && shell_name[1] == '/')
  6389. +-    {
  6390. +-      /* Fast path for common case. */
  6391. +-      char *cdir;
  6392. +-      int len;
  6393. +-
  6394. +-      cdir = get_string_value ("PWD");
  6395. +-      if (cdir)
  6396. +-      {
  6397. +-        len = strlen (cdir);
  6398. +-        name = (char *)xmalloc (len + strlen (shell_name) + 1);
  6399. +-        strcpy (name, cdir);
  6400. +-        strcpy (name + len, shell_name + 1);
  6401. +-      }
  6402. +-      else
  6403. +-      name = savestring (shell_name);
  6404. +-    }
  6405. +-  else
  6406. +-    {
  6407. +-      char *tname;
  6408. +-      int s;
  6409. +-
  6410. +-      tname = find_user_command (shell_name);
  6411. +-
  6412. +-      if (tname == 0)
  6413. +-      {
  6414. +-        /* Try the current directory.  If there is not an executable
  6415. +-           there, just punt and use the login shell. */
  6416. +-        s = file_status (shell_name);
  6417. +-        if (s & FS_EXECABLE)
  6418. +-          {
  6419. +-            tname = make_absolute (shell_name, get_string_value ("PWD"));
  6420. +-            if (*shell_name == '.')
  6421. +-              {
  6422. +-                name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
  6423. +-                if (name == 0)
  6424. +-                  name = tname;
  6425. +-                else
  6426. +-                  free (tname);
  6427. +-              }
  6428. +-           else
  6429. +-              name = tname;
  6430. +-          }
  6431. +-        else
  6432. +-          {
  6433. +-            if (current_user.shell == 0)
  6434. +-              get_current_user_info ();
  6435. +-            name = savestring (current_user.shell);
  6436. +-          }
  6437. +-      }
  6438. +-      else
  6439. +-      {
  6440. +-        name = full_pathname (tname);
  6441. +-        free (tname);
  6442. +-      }
  6443. +-    }
  6444. +-
  6445. +-  return (name);
  6446. +-}
  6447. +-
  6448. +-void
  6449. +-adjust_shell_level (change)
  6450. +-     int change;
  6451. +-{
  6452. +-  char new_level[5], *old_SHLVL;
  6453. +-  intmax_t old_level;
  6454. +-  SHELL_VAR *temp_var;
  6455. +-
  6456. +-  old_SHLVL = get_string_value ("SHLVL");
  6457. +-  if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
  6458. +-    old_level = 0;
  6459. +-
  6460. +-  shell_level = old_level + change;
  6461. +-  if (shell_level < 0)
  6462. +-    shell_level = 0;
  6463. +-  else if (shell_level > 1000)
  6464. +-    {
  6465. +-      internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
  6466. +-      shell_level = 1;
  6467. +-    }
  6468. +-
  6469. +-  /* We don't need the full generality of itos here. */
  6470. +-  if (shell_level < 10)
  6471. +-    {
  6472. +-      new_level[0] = shell_level + '0';
  6473. +-      new_level[1] = '\0';
  6474. +-    }
  6475. +-  else if (shell_level < 100)
  6476. +-    {
  6477. +-      new_level[0] = (shell_level / 10) + '0';
  6478. +-      new_level[1] = (shell_level % 10) + '0';
  6479. +-      new_level[2] = '\0';
  6480. +-    }
  6481. +-  else if (shell_level < 1000)
  6482. +-    {
  6483. +-      new_level[0] = (shell_level / 100) + '0';
  6484. +-      old_level = shell_level % 100;
  6485. +-      new_level[1] = (old_level / 10) + '0';
  6486. +-      new_level[2] = (old_level % 10) + '0';
  6487. +-      new_level[3] = '\0';
  6488. +-    }
  6489. +-
  6490. +-  temp_var = bind_variable ("SHLVL", new_level, 0);
  6491. +-  set_auto_export (temp_var);
  6492. +-}
  6493. +-
  6494. +-static void
  6495. +-initialize_shell_level ()
  6496. +-{
  6497. +-  adjust_shell_level (1);
  6498. +-}
  6499. +-
  6500. +-/* If we got PWD from the environment, update our idea of the current
  6501. +-   working directory.  In any case, make sure that PWD exists before
  6502. +-   checking it.  It is possible for getcwd () to fail on shell startup,
  6503. +-   and in that case, PWD would be undefined.  If this is an interactive
  6504. +-   login shell, see if $HOME is the current working directory, and if
  6505. +-   that's not the same string as $PWD, set PWD=$HOME. */
  6506. +-
  6507. +-void
  6508. +-set_pwd ()
  6509. +-{
  6510. +-  SHELL_VAR *temp_var, *home_var;
  6511. +-  char *temp_string, *home_string;
  6512. +-
  6513. +-  home_var = find_variable ("HOME");
  6514. +-  home_string = home_var ? value_cell (home_var) : (char *)NULL;
  6515. +-
  6516. +-  temp_var = find_variable ("PWD");
  6517. +-  if (temp_var && imported_p (temp_var) &&
  6518. +-      (temp_string = value_cell (temp_var)) &&
  6519. +-      same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
  6520. +-    set_working_directory (temp_string);
  6521. +-  else if (home_string && interactive_shell && login_shell &&
  6522. +-         same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
  6523. +-    {
  6524. +-      set_working_directory (home_string);
  6525. +-      temp_var = bind_variable ("PWD", home_string, 0);
  6526. +-      set_auto_export (temp_var);
  6527. +-    }
  6528. +-  else
  6529. +-    {
  6530. +-      temp_string = get_working_directory ("shell-init");
  6531. +-      if (temp_string)
  6532. +-      {
  6533. +-        temp_var = bind_variable ("PWD", temp_string, 0);
  6534. +-        set_auto_export (temp_var);
  6535. +-        free (temp_string);
  6536. +-      }
  6537. +-    }
  6538. +-
  6539. +-  /* According to the Single Unix Specification, v2, $OLDPWD is an
  6540. +-     `environment variable' and therefore should be auto-exported.
  6541. +-     Make a dummy invisible variable for OLDPWD, and mark it as exported. */
  6542. +-  temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
  6543. +-  VSETATTR (temp_var, (att_exported | att_invisible));
  6544. +-}
  6545. +-
  6546. +-/* Make a variable $PPID, which holds the pid of the shell's parent.  */
  6547. +-void
  6548. +-set_ppid ()
  6549. +-{
  6550. +-  char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
  6551. +-  SHELL_VAR *temp_var;
  6552. +-
  6553. +-  name = inttostr (getppid (), namebuf, sizeof(namebuf));
  6554. +-  temp_var = find_variable ("PPID");
  6555. +-  if (temp_var)
  6556. +-    VUNSETATTR (temp_var, (att_readonly | att_exported));
  6557. +-  temp_var = bind_variable ("PPID", name, 0);
  6558. +-  VSETATTR (temp_var, (att_readonly | att_integer));
  6559. +-}
  6560. +-
  6561. +-static void
  6562. +-uidset ()
  6563. +-{
  6564. +-  char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
  6565. +-  register SHELL_VAR *v;
  6566. +-
  6567. +-  b = inttostr (current_user.uid, buff, sizeof (buff));
  6568. +-  v = find_variable ("UID");
  6569. +-  if (v == 0)
  6570. +-    {
  6571. +-      v = bind_variable ("UID", b, 0);
  6572. +-      VSETATTR (v, (att_readonly | att_integer));
  6573. +-    }
  6574. +-
  6575. +-  if (current_user.euid != current_user.uid)
  6576. +-    b = inttostr (current_user.euid, buff, sizeof (buff));
  6577. +-
  6578. +-  v = find_variable ("EUID");
  6579. +-  if (v == 0)
  6580. +-    {
  6581. +-      v = bind_variable ("EUID", b, 0);
  6582. +-      VSETATTR (v, (att_readonly | att_integer));
  6583. +-    }
  6584. +-}
  6585. +-
  6586. +-#if defined (ARRAY_VARS)
  6587. +-static void
  6588. +-make_vers_array ()
  6589. +-{
  6590. +-  SHELL_VAR *vv;
  6591. +-  ARRAY *av;
  6592. +-  char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
  6593. +-
  6594. +-  unbind_variable ("BASH_VERSINFO");
  6595. +-
  6596. +-  vv = make_new_array_variable ("BASH_VERSINFO");
  6597. +-  av = array_cell (vv);
  6598. +-  strcpy (d, dist_version);
  6599. +-  s = strchr (d, '.');
  6600. +-  if (s)
  6601. +-    *s++ = '\0';
  6602. +-  array_insert (av, 0, d);
  6603. +-  array_insert (av, 1, s);
  6604. +-  s = inttostr (patch_level, b, sizeof (b));
  6605. +-  array_insert (av, 2, s);
  6606. +-  s = inttostr (build_version, b, sizeof (b));
  6607. +-  array_insert (av, 3, s);
  6608. +-  array_insert (av, 4, release_status);
  6609. +-  array_insert (av, 5, MACHTYPE);
  6610. +-
  6611. +-  VSETATTR (vv, att_readonly);
  6612. +-}
  6613. +-#endif /* ARRAY_VARS */
  6614. +-
  6615. +-/* Set the environment variables $LINES and $COLUMNS in response to
  6616. +-   a window size change. */
  6617. +-void
  6618. +-sh_set_lines_and_columns (lines, cols)
  6619. +-     int lines, cols;
  6620. +-{
  6621. +-  char val[INT_STRLEN_BOUND(int) + 1], *v;
  6622. +-
  6623. +-#if defined (READLINE)
  6624. +-  /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
  6625. +-  if (winsize_assignment)
  6626. +-    return;
  6627. +-#endif
  6628. +-
  6629. +-  v = inttostr (lines, val, sizeof (val));
  6630. +-  bind_variable ("LINES", v, 0);
  6631. +-
  6632. +-  v = inttostr (cols, val, sizeof (val));
  6633. +-  bind_variable ("COLUMNS", v, 0);
  6634. +-}
  6635. +-
  6636. +-/* **************************************************************** */
  6637. +-/*                                                                */
  6638. +-/*               Printing variables and values                    */
  6639. +-/*                                                                */
  6640. +-/* **************************************************************** */
  6641. +-
  6642. +-/* Print LIST (a list of shell variables) to stdout in such a way that
  6643. +-   they can be read back in. */
  6644. +-void
  6645. +-print_var_list (list)
  6646. +-     register SHELL_VAR **list;
  6647. +-{
  6648. +-  register int i;
  6649. +-  register SHELL_VAR *var;
  6650. +-
  6651. +-  for (i = 0; list && (var = list[i]); i++)
  6652. +-    if (invisible_p (var) == 0)
  6653. +-      print_assignment (var);
  6654. +-}
  6655. +-
  6656. +-/* Print LIST (a list of shell functions) to stdout in such a way that
  6657. +-   they can be read back in. */
  6658. +-void
  6659. +-print_func_list (list)
  6660. +-     register SHELL_VAR **list;
  6661. +-{
  6662. +-  register int i;
  6663. +-  register SHELL_VAR *var;
  6664. +-
  6665. +-  for (i = 0; list && (var = list[i]); i++)
  6666. +-    {
  6667. +-      printf ("%s ", var->name);
  6668. +-      print_var_function (var);
  6669. +-      printf ("\n");
  6670. +-    }
  6671. +-}
  6672. +-      
  6673. +-/* Print the value of a single SHELL_VAR.  No newline is
  6674. +-   output, but the variable is printed in such a way that
  6675. +-   it can be read back in. */
  6676. +-void
  6677. +-print_assignment (var)
  6678. +-     SHELL_VAR *var;
  6679. +-{
  6680. +-  if (var_isset (var) == 0)
  6681. +-    return;
  6682. +-
  6683. +-  if (function_p (var))
  6684. +-    {
  6685. +-      printf ("%s", var->name);
  6686. +-      print_var_function (var);
  6687. +-      printf ("\n");
  6688. +-    }
  6689. +-#if defined (ARRAY_VARS)
  6690. +-  else if (array_p (var))
  6691. +-    print_array_assignment (var, 0);
  6692. +-  else if (assoc_p (var))
  6693. +-    print_assoc_assignment (var, 0);
  6694. +-#endif /* ARRAY_VARS */
  6695. +-  else
  6696. +-    {
  6697. +-      printf ("%s=", var->name);
  6698. +-      print_var_value (var, 1);
  6699. +-      printf ("\n");
  6700. +-    }
  6701. +-}
  6702. +-
  6703. +-/* Print the value cell of VAR, a shell variable.  Do not print
  6704. +-   the name, nor leading/trailing newline.  If QUOTE is non-zero,
  6705. +-   and the value contains shell metacharacters, quote the value
  6706. +-   in such a way that it can be read back in. */
  6707. +-void
  6708. +-print_var_value (var, quote)
  6709. +-     SHELL_VAR *var;
  6710. +-     int quote;
  6711. +-{
  6712. +-  char *t;
  6713. +-
  6714. +-  if (var_isset (var) == 0)
  6715. +-    return;
  6716. +-
  6717. +-  if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
  6718. +-    {
  6719. +-      t = ansic_quote (value_cell (var), 0, (int *)0);
  6720. +-      printf ("%s", t);
  6721. +-      free (t);
  6722. +-    }
  6723. +-  else if (quote && sh_contains_shell_metas (value_cell (var)))
  6724. +-    {
  6725. +-      t = sh_single_quote (value_cell (var));
  6726. +-      printf ("%s", t);
  6727. +-      free (t);
  6728. +-    }
  6729. +-  else
  6730. +-    printf ("%s", value_cell (var));
  6731. +-}
  6732. +-
  6733. +-/* Print the function cell of VAR, a shell variable.  Do not
  6734. +-   print the name, nor leading/trailing newline. */
  6735. +-void
  6736. +-print_var_function (var)
  6737. +-     SHELL_VAR *var;
  6738. +-{
  6739. +-  char *x;
  6740. +-
  6741. +-  if (function_p (var) && var_isset (var))
  6742. +-    {
  6743. +-      x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
  6744. +-      printf ("%s", x);
  6745. +-    }
  6746. +-}
  6747. +-
  6748. +-/* **************************************************************** */
  6749. +-/*                                                                */
  6750. +-/*                    Dynamic Variables                           */
  6751. +-/*                                                                */
  6752. +-/* **************************************************************** */
  6753. +-
  6754. +-/* DYNAMIC VARIABLES
  6755. +-
  6756. +-   These are variables whose values are generated anew each time they are
  6757. +-   referenced.  These are implemented using a pair of function pointers
  6758. +-   in the struct variable: assign_func, which is called from bind_variable
  6759. +-   and, if arrays are compiled into the shell, some of the functions in
  6760. +-   arrayfunc.c, and dynamic_value, which is called from find_variable.
  6761. +-
  6762. +-   assign_func is called from bind_variable_internal, if
  6763. +-   bind_variable_internal discovers that the variable being assigned to
  6764. +-   has such a function.  The function is called as
  6765. +-      SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
  6766. +-   and the (SHELL_VAR *)temp is returned as the value of bind_variable.  It
  6767. +-   is usually ENTRY (self).  IND is an index for an array variable, and
  6768. +-   unused otherwise.
  6769. +-
  6770. +-   dynamic_value is called from find_variable_internal to return a `new'
  6771. +-   value for the specified dynamic varible.  If this function is NULL,
  6772. +-   the variable is treated as a `normal' shell variable.  If it is not,
  6773. +-   however, then this function is called like this:
  6774. +-      tempvar = (*(var->dynamic_value)) (var);
  6775. +-
  6776. +-   Sometimes `tempvar' will replace the value of `var'.  Other times, the
  6777. +-   shell will simply use the string value.  Pretty object-oriented, huh?
  6778. +-
  6779. +-   Be warned, though: if you `unset' a special variable, it loses its
  6780. +-   special meaning, even if you subsequently set it.
  6781. +-
  6782. +-   The special assignment code would probably have been better put in
  6783. +-   subst.c: do_assignment_internal, in the same style as
  6784. +-   stupidly_hack_special_variables, but I wanted the changes as
  6785. +-   localized as possible.  */
  6786. +-
  6787. +-#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
  6788. +-  do \
  6789. +-    { \
  6790. +-      v = bind_variable (var, (val), 0); \
  6791. +-      v->dynamic_value = gfunc; \
  6792. +-      v->assign_func = afunc; \
  6793. +-    } \
  6794. +-  while (0)
  6795. +-
  6796. +-#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
  6797. +-  do \
  6798. +-    { \
  6799. +-      v = make_new_array_variable (var); \
  6800. +-      v->dynamic_value = gfunc; \
  6801. +-      v->assign_func = afunc; \
  6802. +-    } \
  6803. +-  while (0)
  6804. +-
  6805. +-#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
  6806. +-  do \
  6807. +-    { \
  6808. +-      v = make_new_assoc_variable (var); \
  6809. +-      v->dynamic_value = gfunc; \
  6810. +-      v->assign_func = afunc; \
  6811. +-    } \
  6812. +-  while (0)
  6813. +-
  6814. +-static SHELL_VAR *
  6815. +-null_assign (self, value, unused, key)
  6816. +-     SHELL_VAR *self;
  6817. +-     char *value;
  6818. +-     arrayind_t unused;
  6819. +-     char *key;
  6820. +-{
  6821. +-  return (self);
  6822. +-}
  6823. +-
  6824. +-#if defined (ARRAY_VARS)
  6825. +-static SHELL_VAR *
  6826. +-null_array_assign (self, value, ind, key)
  6827. +-     SHELL_VAR *self;
  6828. +-     char *value;
  6829. +-     arrayind_t ind;
  6830. +-     char *key;
  6831. +-{
  6832. +-  return (self);
  6833. +-}
  6834. +-#endif
  6835. +-
  6836. +-/* Degenerate `dynamic_value' function; just returns what's passed without
  6837. +-   manipulation. */
  6838. +-static SHELL_VAR *
  6839. +-get_self (self)
  6840. +-     SHELL_VAR *self;
  6841. +-{
  6842. +-  return (self);
  6843. +-}
  6844. +-
  6845. +-#if defined (ARRAY_VARS)
  6846. +-/* A generic dynamic array variable initializer.  Initialize array variable
  6847. +-   NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
  6848. +-static SHELL_VAR *
  6849. +-init_dynamic_array_var (name, getfunc, setfunc, attrs)
  6850. +-     char *name;
  6851. +-     sh_var_value_func_t *getfunc;
  6852. +-     sh_var_assign_func_t *setfunc;
  6853. +-     int attrs;
  6854. +-{
  6855. +-  SHELL_VAR *v;
  6856. +-
  6857. +-  v = find_variable (name);
  6858. +-  if (v)
  6859. +-    return (v);
  6860. +-  INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
  6861. +-  if (attrs)
  6862. +-    VSETATTR (v, attrs);
  6863. +-  return v;
  6864. +-}
  6865. +-
  6866. +-static SHELL_VAR *
  6867. +-init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
  6868. +-     char *name;
  6869. +-     sh_var_value_func_t *getfunc;
  6870. +-     sh_var_assign_func_t *setfunc;
  6871. +-     int attrs;
  6872. +-{
  6873. +-  SHELL_VAR *v;
  6874. +-
  6875. +-  v = find_variable (name);
  6876. +-  if (v)
  6877. +-    return (v);
  6878. +-  INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
  6879. +-  if (attrs)
  6880. +-    VSETATTR (v, attrs);
  6881. +-  return v;
  6882. +-}
  6883. +-#endif
  6884. +-
  6885. +-/* The value of $SECONDS.  This is the number of seconds since shell
  6886. +-   invocation, or, the number of seconds since the last assignment + the
  6887. +-   value of the last assignment. */
  6888. +-static intmax_t seconds_value_assigned;
  6889. +-
  6890. +-static SHELL_VAR *
  6891. +-assign_seconds (self, value, unused, key)
  6892. +-     SHELL_VAR *self;
  6893. +-     char *value;
  6894. +-     arrayind_t unused;
  6895. +-     char *key;
  6896. +-{
  6897. +-  if (legal_number (value, &seconds_value_assigned) == 0)
  6898. +-    seconds_value_assigned = 0;
  6899. +-  shell_start_time = NOW;
  6900. +-  return (self);
  6901. +-}
  6902. +-
  6903. +-static SHELL_VAR *
  6904. +-get_seconds (var)
  6905. +-     SHELL_VAR *var;
  6906. +-{
  6907. +-  time_t time_since_start;
  6908. +-  char *p;
  6909. +-
  6910. +-  time_since_start = NOW - shell_start_time;
  6911. +-  p = itos(seconds_value_assigned + time_since_start);
  6912. +-
  6913. +-  FREE (value_cell (var));
  6914. +-
  6915. +-  VSETATTR (var, att_integer);
  6916. +-  var_setvalue (var, p);
  6917. +-  return (var);
  6918. +-}
  6919. +-
  6920. +-static SHELL_VAR *
  6921. +-init_seconds_var ()
  6922. +-{
  6923. +-  SHELL_VAR *v;
  6924. +-
  6925. +-  v = find_variable ("SECONDS");
  6926. +-  if (v)
  6927. +-    {
  6928. +-      if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
  6929. +-      seconds_value_assigned = 0;
  6930. +-    }
  6931. +-  INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
  6932. +-  return v;      
  6933. +-}
  6934. +-    
  6935. +-/* The random number seed.  You can change this by setting RANDOM. */
  6936. +-static unsigned long rseed = 1;
  6937. +-static int last_random_value;
  6938. +-static int seeded_subshell = 0;
  6939. +-
  6940. +-/* A linear congruential random number generator based on the example
  6941. +-   one in the ANSI C standard.  This one isn't very good, but a more
  6942. +-   complicated one is overkill. */
  6943. +-
  6944. +-/* Returns a pseudo-random number between 0 and 32767. */
  6945. +-static int
  6946. +-brand ()
  6947. +-{
  6948. +-  /* From "Random number generators: good ones are hard to find",
  6949. +-     Park and Miller, Communications of the ACM, vol. 31, no. 10,
  6950. +-     October 1988, p. 1195. filtered through FreeBSD */
  6951. +-  long h, l;
  6952. +-
  6953. +-  /* Can't seed with 0. */
  6954. +-  if (rseed == 0)
  6955. +-    rseed = 123459876;
  6956. +-  h = rseed / 127773;
  6957. +-  l = rseed % 127773;
  6958. +-  rseed = 16807 * l - 2836 * h;
  6959. +-#if 0
  6960. +-  if (rseed < 0)
  6961. +-    rseed += 0x7fffffff;
  6962. +-#endif
  6963. +-  return ((unsigned int)(rseed & 32767));     /* was % 32768 */
  6964. +-}
  6965. +-
  6966. +-/* Set the random number generator seed to SEED. */
  6967. +-static void
  6968. +-sbrand (seed)
  6969. +-     unsigned long seed;
  6970. +-{
  6971. +-  rseed = seed;
  6972. +-  last_random_value = 0;
  6973. +-}
  6974. +-
  6975. +-static void
  6976. +-seedrand ()
  6977. +-{
  6978. +-  struct timeval tv;
  6979. +-
  6980. +-  gettimeofday (&tv, NULL);
  6981. +-  sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
  6982. +-}
  6983. +-
  6984. +-static SHELL_VAR *
  6985. +-assign_random (self, value, unused, key)
  6986. +-     SHELL_VAR *self;
  6987. +-     char *value;
  6988. +-     arrayind_t unused;
  6989. +-     char *key;
  6990. +-{
  6991. +-  sbrand (strtoul (value, (char **)NULL, 10));
  6992. +-  if (subshell_environment)
  6993. +-    seeded_subshell = getpid ();
  6994. +-  return (self);
  6995. +-}
  6996. +-
  6997. +-int
  6998. +-get_random_number ()
  6999. +-{
  7000. +-  int rv, pid;
  7001. +-
  7002. +-  /* Reset for command and process substitution. */
  7003. +-  pid = getpid ();
  7004. +-  if (subshell_environment && seeded_subshell != pid)
  7005. +-    {
  7006. +-      seedrand ();
  7007. +-      seeded_subshell = pid;
  7008. +-    }
  7009. +-
  7010. +-  do
  7011. +-    rv = brand ();
  7012. +-  while (rv == last_random_value);
  7013. +-  return rv;
  7014. +-}
  7015. +-
  7016. +-static SHELL_VAR *
  7017. +-get_random (var)
  7018. +-     SHELL_VAR *var;
  7019. +-{
  7020. +-  int rv;
  7021. +-  char *p;
  7022. +-
  7023. +-  rv = get_random_number ();
  7024. +-  last_random_value = rv;
  7025. +-  p = itos (rv);
  7026. +-
  7027. +-  FREE (value_cell (var));
  7028. +-
  7029. +-  VSETATTR (var, att_integer);
  7030. +-  var_setvalue (var, p);
  7031. +-  return (var);
  7032. +-}
  7033. +-
  7034. +-static SHELL_VAR *
  7035. +-assign_lineno (var, value, unused, key)
  7036. +-     SHELL_VAR *var;
  7037. +-     char *value;
  7038. +-     arrayind_t unused;
  7039. +-     char *key;
  7040. +-{
  7041. +-  intmax_t new_value;
  7042. +-
  7043. +-  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
  7044. +-    new_value = 0;
  7045. +-  line_number = line_number_base = new_value;
  7046. +-  return var;
  7047. +-}
  7048. +-
  7049. +-/* Function which returns the current line number. */
  7050. +-static SHELL_VAR *
  7051. +-get_lineno (var)
  7052. +-     SHELL_VAR *var;
  7053. +-{
  7054. +-  char *p;
  7055. +-  int ln;
  7056. +-
  7057. +-  ln = executing_line_number ();
  7058. +-  p = itos (ln);
  7059. +-  FREE (value_cell (var));
  7060. +-  var_setvalue (var, p);
  7061. +-  return (var);
  7062. +-}
  7063. +-
  7064. +-static SHELL_VAR *
  7065. +-assign_subshell (var, value, unused, key)
  7066. +-     SHELL_VAR *var;
  7067. +-     char *value;
  7068. +-     arrayind_t unused;
  7069. +-     char *key;
  7070. +-{
  7071. +-  intmax_t new_value;
  7072. +-
  7073. +-  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
  7074. +-    new_value = 0;
  7075. +-  subshell_level = new_value;
  7076. +-  return var;
  7077. +-}
  7078. +-
  7079. +-static SHELL_VAR *
  7080. +-get_subshell (var)
  7081. +-     SHELL_VAR *var;
  7082. +-{
  7083. +-  char *p;
  7084. +-
  7085. +-  p = itos (subshell_level);
  7086. +-  FREE (value_cell (var));
  7087. +-  var_setvalue (var, p);
  7088. +-  return (var);
  7089. +-}
  7090. +-
  7091. +-static SHELL_VAR *
  7092. +-get_bashpid (var)
  7093. +-     SHELL_VAR *var;
  7094. +-{
  7095. +-  int pid;
  7096. +-  char *p;
  7097. +-
  7098. +-  pid = getpid ();
  7099. +-  p = itos (pid);
  7100. +-
  7101. +-  FREE (value_cell (var));
  7102. +-  VSETATTR (var, att_integer|att_readonly);
  7103. +-  var_setvalue (var, p);
  7104. +-  return (var);
  7105. +-}
  7106. +-
  7107. +-static SHELL_VAR *
  7108. +-get_bash_command (var)
  7109. +-     SHELL_VAR *var;
  7110. +-{
  7111. +-  char *p;
  7112. +-
  7113. +-  if (the_printed_command_except_trap)
  7114. +-    p = savestring (the_printed_command_except_trap);
  7115. +-  else
  7116. +-    {
  7117. +-      p = (char *)xmalloc (1);
  7118. +-      p[0] = '\0';
  7119. +-    }
  7120. +-  FREE (value_cell (var));
  7121. +-  var_setvalue (var, p);
  7122. +-  return (var);
  7123. +-}
  7124. +-
  7125. +-#if defined (HISTORY)
  7126. +-static SHELL_VAR *
  7127. +-get_histcmd (var)
  7128. +-     SHELL_VAR *var;
  7129. +-{
  7130. +-  char *p;
  7131. +-
  7132. +-  p = itos (history_number ());
  7133. +-  FREE (value_cell (var));
  7134. +-  var_setvalue (var, p);
  7135. +-  return (var);
  7136. +-}
  7137. +-#endif
  7138. +-
  7139. +-#if defined (READLINE)
  7140. +-/* When this function returns, VAR->value points to malloced memory. */
  7141. +-static SHELL_VAR *
  7142. +-get_comp_wordbreaks (var)
  7143. +-     SHELL_VAR *var;
  7144. +-{
  7145. +-  /* If we don't have anything yet, assign a default value. */
  7146. +-  if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
  7147. +-    enable_hostname_completion (perform_hostname_completion);
  7148. +-
  7149. +-  FREE (value_cell (var));
  7150. +-  var_setvalue (var, savestring (rl_completer_word_break_characters));
  7151. +-
  7152. +-  return (var);
  7153. +-}
  7154. +-
  7155. +-/* When this function returns, rl_completer_word_break_characters points to
  7156. +-   malloced memory. */
  7157. +-static SHELL_VAR *
  7158. +-assign_comp_wordbreaks (self, value, unused, key)
  7159. +-     SHELL_VAR *self;
  7160. +-     char *value;
  7161. +-     arrayind_t unused;
  7162. +-     char *key;
  7163. +-{
  7164. +-  if (rl_completer_word_break_characters &&
  7165. +-      rl_completer_word_break_characters != rl_basic_word_break_characters)
  7166. +-    free (rl_completer_word_break_characters);
  7167. +-
  7168. +-  rl_completer_word_break_characters = savestring (value);
  7169. +-  return self;
  7170. +-}
  7171. +-#endif /* READLINE */
  7172. +-
  7173. +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  7174. +-static SHELL_VAR *
  7175. +-assign_dirstack (self, value, ind, key)
  7176. +-     SHELL_VAR *self;
  7177. +-     char *value;
  7178. +-     arrayind_t ind;
  7179. +-     char *key;
  7180. +-{
  7181. +-  set_dirstack_element (ind, 1, value);
  7182. +-  return self;
  7183. +-}
  7184. +-
  7185. +-static SHELL_VAR *
  7186. +-get_dirstack (self)
  7187. +-     SHELL_VAR *self;
  7188. +-{
  7189. +-  ARRAY *a;
  7190. +-  WORD_LIST *l;
  7191. +-
  7192. +-  l = get_directory_stack (0);
  7193. +-  a = array_from_word_list (l);
  7194. +-  array_dispose (array_cell (self));
  7195. +-  dispose_words (l);
  7196. +-  var_setarray (self, a);
  7197. +-  return self;
  7198. +-}
  7199. +-#endif /* PUSHD AND POPD && ARRAY_VARS */
  7200. +-
  7201. +-#if defined (ARRAY_VARS)
  7202. +-/* We don't want to initialize the group set with a call to getgroups()
  7203. +-   unless we're asked to, but we only want to do it once. */
  7204. +-static SHELL_VAR *
  7205. +-get_groupset (self)
  7206. +-     SHELL_VAR *self;
  7207. +-{
  7208. +-  register int i;
  7209. +-  int ng;
  7210. +-  ARRAY *a;
  7211. +-  static char **group_set = (char **)NULL;
  7212. +-
  7213. +-  if (group_set == 0)
  7214. +-    {
  7215. +-      group_set = get_group_list (&ng);
  7216. +-      a = array_cell (self);
  7217. +-      for (i = 0; i < ng; i++)
  7218. +-      array_insert (a, i, group_set[i]);
  7219. +-    }
  7220. +-  return (self);
  7221. +-}
  7222. +-
  7223. +-static SHELL_VAR *
  7224. +-build_hashcmd (self)
  7225. +-     SHELL_VAR *self;
  7226. +-{
  7227. +-  HASH_TABLE *h;
  7228. +-  int i;
  7229. +-  char *k, *v;
  7230. +-  BUCKET_CONTENTS *item;
  7231. +-
  7232. +-  h = assoc_cell (self);
  7233. +-  if (h)
  7234. +-    assoc_dispose (h);
  7235. +-
  7236. +-  if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
  7237. +-    {
  7238. +-      var_setvalue (self, (char *)NULL);
  7239. +-      return self;
  7240. +-    }
  7241. +-
  7242. +-  h = assoc_create (hashed_filenames->nbuckets);
  7243. +-  for (i = 0; i < hashed_filenames->nbuckets; i++)
  7244. +-    {
  7245. +-      for (item = hash_items (i, hashed_filenames); item; item = item->next)
  7246. +-      {
  7247. +-        k = savestring (item->key);
  7248. +-        v = pathdata(item)->path;
  7249. +-        assoc_insert (h, k, v);
  7250. +-      }
  7251. +-    }
  7252. +-
  7253. +-  var_setvalue (self, (char *)h);
  7254. +-  return self;
  7255. +-}
  7256. +-
  7257. +-static SHELL_VAR *
  7258. +-get_hashcmd (self)
  7259. +-     SHELL_VAR *self;
  7260. +-{
  7261. +-  build_hashcmd (self);
  7262. +-  return (self);
  7263. +-}
  7264. +-
  7265. +-static SHELL_VAR *
  7266. +-assign_hashcmd (self, value, ind, key)
  7267. +-     SHELL_VAR *self;
  7268. +-     char *value;
  7269. +-     arrayind_t ind;
  7270. +-     char *key;
  7271. +-{
  7272. +-  phash_insert (key, value, 0, 0);
  7273. +-  return (build_hashcmd (self));
  7274. +-}
  7275. +-
  7276. +-#if defined (ALIAS)
  7277. +-static SHELL_VAR *
  7278. +-build_aliasvar (self)
  7279. +-     SHELL_VAR *self;
  7280. +-{
  7281. +-  HASH_TABLE *h;
  7282. +-  int i;
  7283. +-  char *k, *v;
  7284. +-  BUCKET_CONTENTS *item;
  7285. +-
  7286. +-  h = assoc_cell (self);
  7287. +-  if (h)
  7288. +-    assoc_dispose (h);
  7289. +-
  7290. +-  if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
  7291. +-    {
  7292. +-      var_setvalue (self, (char *)NULL);
  7293. +-      return self;
  7294. +-    }
  7295. +-
  7296. +-  h = assoc_create (aliases->nbuckets);
  7297. +-  for (i = 0; i < aliases->nbuckets; i++)
  7298. +-    {
  7299. +-      for (item = hash_items (i, aliases); item; item = item->next)
  7300. +-      {
  7301. +-        k = savestring (item->key);
  7302. +-        v = ((alias_t *)(item->data))->value;
  7303. +-        assoc_insert (h, k, v);
  7304. +-      }
  7305. +-    }
  7306. +-
  7307. +-  var_setvalue (self, (char *)h);
  7308. +-  return self;
  7309. +-}
  7310. +-
  7311. +-static SHELL_VAR *
  7312. +-get_aliasvar (self)
  7313. +-     SHELL_VAR *self;
  7314. +-{
  7315. +-  build_aliasvar (self);
  7316. +-  return (self);
  7317. +-}
  7318. +-
  7319. +-static SHELL_VAR *
  7320. +-assign_aliasvar (self, value, ind, key)
  7321. +-     SHELL_VAR *self;
  7322. +-     char *value;
  7323. +-     arrayind_t ind;
  7324. +-     char *key;
  7325. +-{
  7326. +-  add_alias (key, value);
  7327. +-  return (build_aliasvar (self));
  7328. +-}
  7329. +-#endif /* ALIAS */
  7330. +-
  7331. +-#endif /* ARRAY_VARS */
  7332. +-
  7333. +-/* If ARRAY_VARS is not defined, this just returns the name of any
  7334. +-   currently-executing function.  If we have arrays, it's a call stack. */
  7335. +-static SHELL_VAR *
  7336. +-get_funcname (self)
  7337. +-     SHELL_VAR *self;
  7338. +-{
  7339. +-#if ! defined (ARRAY_VARS)
  7340. +-  char *t;
  7341. +-  if (variable_context && this_shell_function)
  7342. +-    {
  7343. +-      FREE (value_cell (self));
  7344. +-      t = savestring (this_shell_function->name);
  7345. +-      var_setvalue (self, t);
  7346. +-    }
  7347. +-#endif
  7348. +-  return (self);
  7349. +-}
  7350. +-
  7351. +-void
  7352. +-make_funcname_visible (on_or_off)
  7353. +-     int on_or_off;
  7354. +-{
  7355. +-  SHELL_VAR *v;
  7356. +-
  7357. +-  v = find_variable ("FUNCNAME");
  7358. +-  if (v == 0 || v->dynamic_value == 0)
  7359. +-    return;
  7360. +-
  7361. +-  if (on_or_off)
  7362. +-    VUNSETATTR (v, att_invisible);
  7363. +-  else
  7364. +-    VSETATTR (v, att_invisible);
  7365. +-}
  7366. +-
  7367. +-static SHELL_VAR *
  7368. +-init_funcname_var ()
  7369. +-{
  7370. +-  SHELL_VAR *v;
  7371. +-
  7372. +-  v = find_variable ("FUNCNAME");
  7373. +-  if (v)
  7374. +-    return v;
  7375. +-#if defined (ARRAY_VARS)
  7376. +-  INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
  7377. +-#else
  7378. +-  INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
  7379. +-#endif
  7380. +-  VSETATTR (v, att_invisible|att_noassign);
  7381. +-  return v;
  7382. +-}
  7383. +-
  7384. +-static void
  7385. +-initialize_dynamic_variables ()
  7386. +-{
  7387. +-  SHELL_VAR *v;
  7388. +-
  7389. +-  v = init_seconds_var ();
  7390. +-
  7391. +-  INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
  7392. +-  INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
  7393. +-
  7394. +-  INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
  7395. +-  VSETATTR (v, att_integer);
  7396. +-  INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
  7397. +-  VSETATTR (v, att_integer);
  7398. +-
  7399. +-  INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
  7400. +-  VSETATTR (v, att_integer|att_readonly);
  7401. +-
  7402. +-#if defined (HISTORY)
  7403. +-  INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
  7404. +-  VSETATTR (v, att_integer);
  7405. +-#endif
  7406. +-
  7407. +-#if defined (READLINE)
  7408. +-  INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
  7409. +-#endif
  7410. +-
  7411. +-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  7412. +-  v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
  7413. +-#endif /* PUSHD_AND_POPD && ARRAY_VARS */
  7414. +-
  7415. +-#if defined (ARRAY_VARS)
  7416. +-  v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
  7417. +-
  7418. +-#  if defined (DEBUGGER)
  7419. +-  v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
  7420. +-  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
  7421. +-#  endif /* DEBUGGER */
  7422. +-  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
  7423. +-  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
  7424. +-
  7425. +-  v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
  7426. +-#  if defined (ALIAS)
  7427. +-  v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
  7428. +-#  endif
  7429. +-#endif
  7430. +-
  7431. +-  v = init_funcname_var ();
  7432. +-}
  7433. +-
  7434. +-/* **************************************************************** */
  7435. +-/*                                                                */
  7436. +-/*            Retrieving variables and values                     */