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                     */
  7437. +-/*                                                                */
  7438. +-/* **************************************************************** */
  7439. +-
  7440. +-/* How to get a pointer to the shell variable or function named NAME.
  7441. +-   HASHED_VARS is a pointer to the hash table containing the list
  7442. +-   of interest (either variables or functions). */
  7443. +-
  7444. +-static SHELL_VAR *
  7445. +-hash_lookup (name, hashed_vars)
  7446. +-     const char *name;
  7447. +-     HASH_TABLE *hashed_vars;
  7448. +-{
  7449. +-  BUCKET_CONTENTS *bucket;
  7450. +-
  7451. +-  bucket = hash_search (name, hashed_vars, 0);
  7452. +-  /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
  7453. +-     table. */
  7454. +-  if (bucket)
  7455. +-    last_table_searched = hashed_vars;
  7456. +-  return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
  7457. +-}
  7458. +-
  7459. +-SHELL_VAR *
  7460. +-var_lookup (name, vcontext)
  7461. +-     const char *name;
  7462. +-     VAR_CONTEXT *vcontext;
  7463. +-{
  7464. +-  VAR_CONTEXT *vc;
  7465. +-  SHELL_VAR *v;
  7466. +-
  7467. +-  v = (SHELL_VAR *)NULL;
  7468. +-  for (vc = vcontext; vc; vc = vc->down)
  7469. +-    if (v = hash_lookup (name, vc->table))
  7470. +-      break;
  7471. +-
  7472. +-  return v;
  7473. +-}
  7474. +-
  7475. +-/* Look up the variable entry named NAME.  If SEARCH_TEMPENV is non-zero,
  7476. +-   then also search the temporarily built list of exported variables.
  7477. +-   The lookup order is:
  7478. +-      temporary_env
  7479. +-      shell_variables list
  7480. +-*/
  7481. +-
  7482. +-SHELL_VAR *
  7483. +-find_variable_internal (name, force_tempenv)
  7484. +-     const char *name;
  7485. +-     int force_tempenv;
  7486. +-{
  7487. +-  SHELL_VAR *var;
  7488. +-  int search_tempenv;
  7489. +-  VAR_CONTEXT *vc;
  7490. +-
  7491. +-  var = (SHELL_VAR *)NULL;
  7492. +-
  7493. +-  /* If explicitly requested, first look in the temporary environment for
  7494. +-     the variable.  This allows constructs such as "foo=x eval 'echo $foo'"
  7495. +-     to get the `exported' value of $foo.  This happens if we are executing
  7496. +-     a function or builtin, or if we are looking up a variable in a
  7497. +-     "subshell environment". */
  7498. +-  search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
  7499. +-
  7500. +-  if (search_tempenv && temporary_env)               
  7501. +-    var = hash_lookup (name, temporary_env);
  7502. +-
  7503. +-  vc = shell_variables;
  7504. +-#if 0
  7505. +-if (search_tempenv == 0 && /* (subshell_environment & SUBSHELL_COMSUB) && */
  7506. +-    expanding_redir &&
  7507. +-    (this_shell_builtin == eval_builtin || this_shell_builtin == command_builtin))
  7508. +-  {
  7509. +-  itrace("find_variable_internal: search_tempenv == 0: skipping VC_BLTNENV");
  7510. +-  while (vc && (vc->flags & VC_BLTNENV))
  7511. +-    vc = vc->down;
  7512. +-  if (vc == 0)
  7513. +-    vc = shell_variables;
  7514. +-  }
  7515. +-#endif
  7516. +-
  7517. +-  if (var == 0)
  7518. +-    var = var_lookup (name, vc);
  7519. +-
  7520. +-  if (var == 0)
  7521. +-    return ((SHELL_VAR *)NULL);
  7522. +-
  7523. +-  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  7524. +-}
  7525. +-
  7526. +-/* Look up and resolve the chain of nameref variables starting at V all the
  7527. +-   way to NULL or non-nameref. */
  7528. +-SHELL_VAR *
  7529. +-find_variable_nameref (v)
  7530. +-     SHELL_VAR *v;
  7531. +-{
  7532. +-  int level;
  7533. +-  char *newname;
  7534. +-  SHELL_VAR *orig, *oldv;
  7535. +-
  7536. +-  level = 0;
  7537. +-  orig = v;
  7538. +-  while (v && nameref_p (v))
  7539. +-    {
  7540. +-      level++;
  7541. +-      if (level > NAMEREF_MAX)
  7542. +-      return ((SHELL_VAR *)0);        /* error message here? */
  7543. +-      newname = nameref_cell (v);
  7544. +-      if (newname == 0 || *newname == '\0')
  7545. +-      return ((SHELL_VAR *)0);
  7546. +-      oldv = v;
  7547. +-      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  7548. +-      if (v == orig || v == oldv)
  7549. +-      {
  7550. +-        internal_warning (_("%s: circular name reference"), orig->name);
  7551. +-        return ((SHELL_VAR *)0);
  7552. +-      }
  7553. +-    }
  7554. +-  return v;
  7555. +-}
  7556. +-
  7557. +-/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
  7558. +-SHELL_VAR *
  7559. +-find_variable_last_nameref (name)
  7560. +-     const char *name;
  7561. +-{
  7562. +-  SHELL_VAR *v, *nv;
  7563. +-  char *newname;
  7564. +-  int level;
  7565. +-
  7566. +-  nv = v = find_variable_noref (name);
  7567. +-  level = 0;
  7568. +-  while (v && nameref_p (v))
  7569. +-    {
  7570. +-      level++;
  7571. +-      if (level > NAMEREF_MAX)
  7572. +-        return ((SHELL_VAR *)0);      /* error message here? */
  7573. +-      newname = nameref_cell (v);
  7574. +-      if (newname == 0 || *newname == '\0')
  7575. +-      return ((SHELL_VAR *)0);
  7576. +-      nv = v;
  7577. +-      v = find_variable_internal (newname, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  7578. +-    }
  7579. +-  return nv;
  7580. +-}
  7581. +-
  7582. +-/* Resolve the chain of nameref variables for NAME.  XXX - could change later */
  7583. +-SHELL_VAR *
  7584. +-find_global_variable_last_nameref (name)
  7585. +-     const char *name;
  7586. +-{
  7587. +-  SHELL_VAR *v, *nv;
  7588. +-  char *newname;
  7589. +-  int level;
  7590. +-
  7591. +-  nv = v = find_global_variable_noref (name);
  7592. +-  level = 0;
  7593. +-  while (v && nameref_p (v))
  7594. +-    {
  7595. +-      level++;
  7596. +-      if (level > NAMEREF_MAX)
  7597. +-        return ((SHELL_VAR *)0);      /* error message here? */
  7598. +-      newname = nameref_cell (v);
  7599. +-      if (newname == 0 || *newname == '\0')
  7600. +-      return ((SHELL_VAR *)0);
  7601. +-      nv = v;
  7602. +-      v = find_global_variable_noref (newname);
  7603. +-    }
  7604. +-  return nv;
  7605. +-}
  7606. +-
  7607. +-static SHELL_VAR *
  7608. +-find_nameref_at_context (v, vc)
  7609. +-     SHELL_VAR *v;
  7610. +-     VAR_CONTEXT *vc;
  7611. +-{
  7612. +-  SHELL_VAR *nv, *nv2;
  7613. +-  VAR_CONTEXT *nvc;
  7614. +-  char *newname;
  7615. +-  int level;
  7616. +-
  7617. +-  nv = v;
  7618. +-  level = 1;
  7619. +-  while (nv && nameref_p (nv))
  7620. +-    {
  7621. +-      level++;
  7622. +-      if (level > NAMEREF_MAX)
  7623. +-        return ((SHELL_VAR *)NULL);
  7624. +-      newname = nameref_cell (nv);
  7625. +-      if (newname == 0 || *newname == '\0')
  7626. +-        return ((SHELL_VAR *)NULL);      
  7627. +-      nv2 = hash_lookup (newname, vc->table);
  7628. +-      if (nv2 == 0)
  7629. +-        break;
  7630. +-      nv = nv2;
  7631. +-    }
  7632. +-  return nv;
  7633. +-}
  7634. +-
  7635. +-/* Do nameref resolution from the VC, which is the local context for some
  7636. +-   function or builtin, `up' the chain to the global variables context.  If
  7637. +-   NVCP is not NULL, return the variable context where we finally ended the
  7638. +-   nameref resolution (so the bind_variable_internal can use the correct
  7639. +-   variable context and hash table). */
  7640. +-static SHELL_VAR *
  7641. +-find_variable_nameref_context (v, vc, nvcp)
  7642. +-     SHELL_VAR *v;
  7643. +-     VAR_CONTEXT *vc;
  7644. +-     VAR_CONTEXT **nvcp;
  7645. +-{
  7646. +-  SHELL_VAR *nv, *nv2;
  7647. +-  VAR_CONTEXT *nvc;
  7648. +-
  7649. +-  /* Look starting at the current context all the way `up' */
  7650. +-  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
  7651. +-    {
  7652. +-      nv2 = find_nameref_at_context (nv, nvc);
  7653. +-      if (nv2 == 0)
  7654. +-        continue;
  7655. +-      nv = nv2;
  7656. +-      if (*nvcp)
  7657. +-        *nvcp = nvc;
  7658. +-      if (nameref_p (nv) == 0)
  7659. +-        break;
  7660. +-    }
  7661. +-  return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
  7662. +-}
  7663. +-
  7664. +-/* Do nameref resolution from the VC, which is the local context for some
  7665. +-   function or builtin, `up' the chain to the global variables context.  If
  7666. +-   NVCP is not NULL, return the variable context where we finally ended the
  7667. +-   nameref resolution (so the bind_variable_internal can use the correct
  7668. +-   variable context and hash table). */
  7669. +-static SHELL_VAR *
  7670. +-find_variable_last_nameref_context (v, vc, nvcp)
  7671. +-     SHELL_VAR *v;
  7672. +-     VAR_CONTEXT *vc;
  7673. +-     VAR_CONTEXT **nvcp;
  7674. +-{
  7675. +-  SHELL_VAR *nv, *nv2;
  7676. +-  VAR_CONTEXT *nvc;
  7677. +-
  7678. +-  /* Look starting at the current context all the way `up' */
  7679. +-  for (nv = v, nvc = vc; nvc; nvc = nvc->down)
  7680. +-    {
  7681. +-      nv2 = find_nameref_at_context (nv, nvc);
  7682. +-      if (nv2 == 0)
  7683. +-      continue;
  7684. +-      nv = nv2;
  7685. +-      if (*nvcp)
  7686. +-        *nvcp = nvc;
  7687. +-    }
  7688. +-  return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
  7689. +-}
  7690. +-
  7691. +-/* Find a variable, forcing a search of the temporary environment first */
  7692. +-SHELL_VAR *
  7693. +-find_variable_tempenv (name)
  7694. +-     const char *name;
  7695. +-{
  7696. +-  SHELL_VAR *var;
  7697. +-
  7698. +-  var = find_variable_internal (name, 1);
  7699. +-  if (var && nameref_p (var))
  7700. +-    var = find_variable_nameref (var);
  7701. +-  return (var);
  7702. +-}
  7703. +-
  7704. +-/* Find a variable, not forcing a search of the temporary environment first */
  7705. +-SHELL_VAR *
  7706. +-find_variable_notempenv (name)
  7707. +-     const char *name;
  7708. +-{
  7709. +-  SHELL_VAR *var;
  7710. +-
  7711. +-  var = find_variable_internal (name, 0);
  7712. +-  if (var && nameref_p (var))
  7713. +-    var = find_variable_nameref (var);
  7714. +-  return (var);
  7715. +-}
  7716. +-
  7717. +-SHELL_VAR *
  7718. +-find_global_variable (name)
  7719. +-     const char *name;
  7720. +-{
  7721. +-  SHELL_VAR *var;
  7722. +-
  7723. +-  var = var_lookup (name, global_variables);
  7724. +-  if (var && nameref_p (var))
  7725. +-    var = find_variable_nameref (var);
  7726. +-
  7727. +-  if (var == 0)
  7728. +-    return ((SHELL_VAR *)NULL);
  7729. +-
  7730. +-  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  7731. +-}
  7732. +-
  7733. +-SHELL_VAR *
  7734. +-find_global_variable_noref (name)
  7735. +-     const char *name;
  7736. +-{
  7737. +-  SHELL_VAR *var;
  7738. +-
  7739. +-  var = var_lookup (name, global_variables);
  7740. +-
  7741. +-  if (var == 0)
  7742. +-    return ((SHELL_VAR *)NULL);
  7743. +-
  7744. +-  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  7745. +-}
  7746. +-
  7747. +-SHELL_VAR *
  7748. +-find_shell_variable (name)
  7749. +-     const char *name;
  7750. +-{
  7751. +-  SHELL_VAR *var;
  7752. +-
  7753. +-  var = var_lookup (name, shell_variables);
  7754. +-  if (var && nameref_p (var))
  7755. +-    var = find_variable_nameref (var);
  7756. +-
  7757. +-  if (var == 0)
  7758. +-    return ((SHELL_VAR *)NULL);
  7759. +-
  7760. +-  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
  7761. +-}
  7762. +-
  7763. +-/* Look up the variable entry named NAME.  Returns the entry or NULL. */
  7764. +-SHELL_VAR *
  7765. +-find_variable (name)
  7766. +-     const char *name;
  7767. +-{
  7768. +-  SHELL_VAR *v;
  7769. +-
  7770. +-  last_table_searched = 0;
  7771. +-  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  7772. +-  if (v && nameref_p (v))
  7773. +-    v = find_variable_nameref (v);
  7774. +-  return v;
  7775. +-}
  7776. +-
  7777. +-SHELL_VAR *
  7778. +-find_variable_noref (name)
  7779. +-     const char *name;
  7780. +-{
  7781. +-  SHELL_VAR *v;
  7782. +-
  7783. +-  v = find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin)));
  7784. +-  return v;
  7785. +-}
  7786. +-
  7787. +-/* Look up the function entry whose name matches STRING.
  7788. +-   Returns the entry or NULL. */
  7789. +-SHELL_VAR *
  7790. +-find_function (name)
  7791. +-     const char *name;
  7792. +-{
  7793. +-  return (hash_lookup (name, shell_functions));
  7794. +-}
  7795. +-
  7796. +-/* Find the function definition for the shell function named NAME.  Returns
  7797. +-   the entry or NULL. */
  7798. +-FUNCTION_DEF *
  7799. +-find_function_def (name)
  7800. +-     const char *name;
  7801. +-{
  7802. +-#if defined (DEBUGGER)
  7803. +-  return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
  7804. +-#else
  7805. +-  return ((FUNCTION_DEF *)0);
  7806. +-#endif
  7807. +-}
  7808. +-
  7809. +-/* Return the value of VAR.  VAR is assumed to have been the result of a
  7810. +-   lookup without any subscript, if arrays are compiled into the shell. */
  7811. +-char *
  7812. +-get_variable_value (var)
  7813. +-     SHELL_VAR *var;
  7814. +-{
  7815. +-  if (var == 0)
  7816. +-    return ((char *)NULL);
  7817. +-#if defined (ARRAY_VARS)
  7818. +-  else if (array_p (var))
  7819. +-    return (array_reference (array_cell (var), 0));
  7820. +-  else if (assoc_p (var))
  7821. +-    return (assoc_reference (assoc_cell (var), "0"));
  7822. +-#endif
  7823. +-  else
  7824. +-    return (value_cell (var));
  7825. +-}
  7826. +-
  7827. +-/* Return the string value of a variable.  Return NULL if the variable
  7828. +-   doesn't exist.  Don't cons a new string.  This is a potential memory
  7829. +-   leak if the variable is found in the temporary environment.  Since
  7830. +-   functions and variables have separate name spaces, returns NULL if
  7831. +-   var_name is a shell function only. */
  7832. +-char *
  7833. +-get_string_value (var_name)
  7834. +-     const char *var_name;
  7835. +-{
  7836. +-  SHELL_VAR *var;
  7837. +-
  7838. +-  var = find_variable (var_name);
  7839. +-  return ((var) ? get_variable_value (var) : (char *)NULL);
  7840. +-}
  7841. +-
  7842. +-/* This is present for use by the tilde and readline libraries. */
  7843. +-char *
  7844. +-sh_get_env_value (v)
  7845. +-     const char *v;
  7846. +-{
  7847. +-  return get_string_value (v);
  7848. +-}
  7849. +-
  7850. +-/* **************************************************************** */
  7851. +-/*                                                                */
  7852. +-/*              Creating and setting variables                    */
  7853. +-/*                                                                */
  7854. +-/* **************************************************************** */
  7855. +-
  7856. +-/* Set NAME to VALUE if NAME has no value. */
  7857. +-SHELL_VAR *
  7858. +-set_if_not (name, value)
  7859. +-     char *name, *value;
  7860. +-{
  7861. +-  SHELL_VAR *v;
  7862. +-
  7863. +-  if (shell_variables == 0)
  7864. +-    create_variable_tables ();
  7865. +-
  7866. +-  v = find_variable (name);
  7867. +-  if (v == 0)
  7868. +-    v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
  7869. +-  return (v);
  7870. +-}
  7871. +-
  7872. +-/* Create a local variable referenced by NAME. */
  7873. +-SHELL_VAR *
  7874. +-make_local_variable (name)
  7875. +-     const char *name;
  7876. +-{
  7877. +-  SHELL_VAR *new_var, *old_var;
  7878. +-  VAR_CONTEXT *vc;
  7879. +-  int was_tmpvar;
  7880. +-  char *tmp_value;
  7881. +-
  7882. +-  /* local foo; local foo;  is a no-op. */
  7883. +-  old_var = find_variable (name);
  7884. +-  if (old_var && local_p (old_var) && old_var->context == variable_context)
  7885. +-    return (old_var);
  7886. +-
  7887. +-  was_tmpvar = old_var && tempvar_p (old_var);
  7888. +-  /* If we're making a local variable in a shell function, the temporary env
  7889. +-     has already been merged into the function's variable context stack.  We
  7890. +-     can assume that a temporary var in the same context appears in the same
  7891. +-     VAR_CONTEXT and can safely be returned without creating a new variable
  7892. +-     (which results in duplicate names in the same VAR_CONTEXT->table */
  7893. +-  /* We can't just test tmpvar_p because variables in the temporary env given
  7894. +-     to a shell function appear in the function's local variable VAR_CONTEXT
  7895. +-     but retain their tempvar attribute.  We want temporary variables that are
  7896. +-     found in temporary_env, hence the test for last_table_searched, which is
  7897. +-     set in hash_lookup and only (so far) checked here. */
  7898. +-  if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
  7899. +-    {
  7900. +-      VUNSETATTR (old_var, att_invisible);
  7901. +-      return (old_var);
  7902. +-    }
  7903. +-  if (was_tmpvar)
  7904. +-    tmp_value = value_cell (old_var);
  7905. +-
  7906. +-  for (vc = shell_variables; vc; vc = vc->down)
  7907. +-    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  7908. +-      break;
  7909. +-
  7910. +-  if (vc == 0)
  7911. +-    {
  7912. +-      internal_error (_("make_local_variable: no function context at current scope"));
  7913. +-      return ((SHELL_VAR *)NULL);
  7914. +-    }
  7915. +-  else if (vc->table == 0)
  7916. +-    vc->table = hash_create (TEMPENV_HASH_BUCKETS);
  7917. +-
  7918. +-  /* Since this is called only from the local/declare/typeset code, we can
  7919. +-     call builtin_error here without worry (of course, it will also work
  7920. +-     for anything that sets this_command_name).  Variables with the `noassign'
  7921. +-     attribute may not be made local.  The test against old_var's context
  7922. +-     level is to disallow local copies of readonly global variables (since I
  7923. +-     believe that this could be a security hole).  Readonly copies of calling
  7924. +-     function local variables are OK. */
  7925. +-  if (old_var && (noassign_p (old_var) ||
  7926. +-               (readonly_p (old_var) && old_var->context == 0)))
  7927. +-    {
  7928. +-      if (readonly_p (old_var))
  7929. +-      sh_readonly (name);
  7930. +-      else if (noassign_p (old_var))
  7931. +-      builtin_error (_("%s: variable may not be assigned value"), name);
  7932. +-#if 0
  7933. +-      /* Let noassign variables through with a warning */
  7934. +-      if (readonly_p (old_var))
  7935. +-#endif
  7936. +-      return ((SHELL_VAR *)NULL);
  7937. +-    }
  7938. +-
  7939. +-  if (old_var == 0)
  7940. +-    new_var = make_new_variable (name, vc->table);
  7941. +-  else
  7942. +-    {
  7943. +-      new_var = make_new_variable (name, vc->table);
  7944. +-
  7945. +-      /* If we found this variable in one of the temporary environments,
  7946. +-       inherit its value.  Watch to see if this causes problems with
  7947. +-       things like `x=4 local x'. XXX - see above for temporary env
  7948. +-       variables with the same context level as variable_context */
  7949. +-      /* XXX - we should only do this if the variable is not an array. */
  7950. +-      if (was_tmpvar)
  7951. +-      var_setvalue (new_var, savestring (tmp_value));
  7952. +-
  7953. +-      new_var->attributes = exported_p (old_var) ? att_exported : 0;
  7954. +-    }
  7955. +-
  7956. +-  vc->flags |= VC_HASLOCAL;
  7957. +-
  7958. +-  new_var->context = variable_context;
  7959. +-  VSETATTR (new_var, att_local);
  7960. +-
  7961. +-  if (ifsname (name))
  7962. +-    setifs (new_var);
  7963. +-
  7964. +-  if (was_tmpvar == 0)
  7965. +-    VSETATTR (new_var, att_invisible);        /* XXX */
  7966. +-  return (new_var);
  7967. +-}
  7968. +-
  7969. +-/* Create a new shell variable with name NAME. */
  7970. +-static SHELL_VAR *
  7971. +-new_shell_variable (name)
  7972. +-     const char *name;
  7973. +-{
  7974. +-  SHELL_VAR *entry;
  7975. +-
  7976. +-  entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  7977. +-
  7978. +-  entry->name = savestring (name);
  7979. +-  var_setvalue (entry, (char *)NULL);
  7980. +-  CLEAR_EXPORTSTR (entry);
  7981. +-
  7982. +-  entry->dynamic_value = (sh_var_value_func_t *)NULL;
  7983. +-  entry->assign_func = (sh_var_assign_func_t *)NULL;
  7984. +-
  7985. +-  entry->attributes = 0;
  7986. +-
  7987. +-  /* Always assume variables are to be made at toplevel!
  7988. +-     make_local_variable has the responsibility of changing the
  7989. +-     variable context. */
  7990. +-  entry->context = 0;
  7991. +-
  7992. +-  return (entry);
  7993. +-}
  7994. +-
  7995. +-/* Create a new shell variable with name NAME and add it to the hash table
  7996. +-   TABLE. */
  7997. +-static SHELL_VAR *
  7998. +-make_new_variable (name, table)
  7999. +-     const char *name;
  8000. +-     HASH_TABLE *table;
  8001. +-{
  8002. +-  SHELL_VAR *entry;
  8003. +-  BUCKET_CONTENTS *elt;
  8004. +-
  8005. +-  entry = new_shell_variable (name);
  8006. +-
  8007. +-  /* Make sure we have a shell_variables hash table to add to. */
  8008. +-  if (shell_variables == 0)
  8009. +-    create_variable_tables ();
  8010. +-
  8011. +-  elt = hash_insert (savestring (name), table, HASH_NOSRCH);
  8012. +-  elt->data = (PTR_T)entry;
  8013. +-
  8014. +-  return entry;
  8015. +-}
  8016. +-
  8017. +-#if defined (ARRAY_VARS)
  8018. +-SHELL_VAR *
  8019. +-make_new_array_variable (name)
  8020. +-     char *name;
  8021. +-{
  8022. +-  SHELL_VAR *entry;
  8023. +-  ARRAY *array;
  8024. +-
  8025. +-  entry = make_new_variable (name, global_variables->table);
  8026. +-  array = array_create ();
  8027. +-
  8028. +-  var_setarray (entry, array);
  8029. +-  VSETATTR (entry, att_array);
  8030. +-  return entry;
  8031. +-}
  8032. +-
  8033. +-SHELL_VAR *
  8034. +-make_local_array_variable (name, assoc_ok)
  8035. +-     char *name;
  8036. +-     int assoc_ok;
  8037. +-{
  8038. +-  SHELL_VAR *var;
  8039. +-  ARRAY *array;
  8040. +-
  8041. +-  var = make_local_variable (name);
  8042. +-  if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
  8043. +-    return var;
  8044. +-
  8045. +-  array = array_create ();
  8046. +-
  8047. +-  dispose_variable_value (var);
  8048. +-  var_setarray (var, array);
  8049. +-  VSETATTR (var, att_array);
  8050. +-  return var;
  8051. +-}
  8052. +-
  8053. +-SHELL_VAR *
  8054. +-make_new_assoc_variable (name)
  8055. +-     char *name;
  8056. +-{
  8057. +-  SHELL_VAR *entry;
  8058. +-  HASH_TABLE *hash;
  8059. +-
  8060. +-  entry = make_new_variable (name, global_variables->table);
  8061. +-  hash = assoc_create (0);
  8062. +-
  8063. +-  var_setassoc (entry, hash);
  8064. +-  VSETATTR (entry, att_assoc);
  8065. +-  return entry;
  8066. +-}
  8067. +-
  8068. +-SHELL_VAR *
  8069. +-make_local_assoc_variable (name)
  8070. +-     char *name;
  8071. +-{
  8072. +-  SHELL_VAR *var;
  8073. +-  HASH_TABLE *hash;
  8074. +-
  8075. +-  var = make_local_variable (name);
  8076. +-  if (var == 0 || assoc_p (var))
  8077. +-    return var;
  8078. +-
  8079. +-  dispose_variable_value (var);
  8080. +-  hash = assoc_create (0);
  8081. +-
  8082. +-  var_setassoc (var, hash);
  8083. +-  VSETATTR (var, att_assoc);
  8084. +-  return var;
  8085. +-}
  8086. +-#endif
  8087. +-
  8088. +-char *
  8089. +-make_variable_value (var, value, flags)
  8090. +-     SHELL_VAR *var;
  8091. +-     char *value;
  8092. +-     int flags;
  8093. +-{
  8094. +-  char *retval, *oval;
  8095. +-  intmax_t lval, rval;
  8096. +-  int expok, olen, op;
  8097. +-
  8098. +-  /* If this variable has had its type set to integer (via `declare -i'),
  8099. +-     then do expression evaluation on it and store the result.  The
  8100. +-     functions in expr.c (evalexp()) and bind_int_variable() are responsible
  8101. +-     for turning off the integer flag if they don't want further
  8102. +-     evaluation done. */
  8103. +-  if (integer_p (var))
  8104. +-    {
  8105. +-      if (flags & ASS_APPEND)
  8106. +-      {
  8107. +-        oval = value_cell (var);
  8108. +-        lval = evalexp (oval, &expok);        /* ksh93 seems to do this */
  8109. +-        if (expok == 0)
  8110. +-          {
  8111. +-            top_level_cleanup ();
  8112. +-            jump_to_top_level (DISCARD);
  8113. +-          }
  8114. +-      }
  8115. +-      rval = evalexp (value, &expok);
  8116. +-      if (expok == 0)
  8117. +-      {
  8118. +-        top_level_cleanup ();
  8119. +-        jump_to_top_level (DISCARD);
  8120. +-      }
  8121. +-      /* This can be fooled if the variable's value changes while evaluating
  8122. +-       `rval'.  We can change it if we move the evaluation of lval to here. */
  8123. +-      if (flags & ASS_APPEND)
  8124. +-      rval += lval;
  8125. +-      retval = itos (rval);
  8126. +-    }
  8127. +-#if defined (CASEMOD_ATTRS)
  8128. +-  else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
  8129. +-    {
  8130. +-      if (flags & ASS_APPEND)
  8131. +-      {
  8132. +-        oval = get_variable_value (var);
  8133. +-        if (oval == 0)        /* paranoia */
  8134. +-          oval = "";
  8135. +-        olen = STRLEN (oval);
  8136. +-        retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
  8137. +-        strcpy (retval, oval);
  8138. +-        if (value)
  8139. +-          strcpy (retval+olen, value);
  8140. +-      }
  8141. +-      else if (*value)
  8142. +-      retval = savestring (value);
  8143. +-      else
  8144. +-      {
  8145. +-        retval = (char *)xmalloc (1);
  8146. +-        retval[0] = '\0';
  8147. +-      }
  8148. +-      op = capcase_p (var) ? CASE_CAPITALIZE
  8149. +-                       : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
  8150. +-      oval = sh_modcase (retval, (char *)0, op);
  8151. +-      free (retval);
  8152. +-      retval = oval;
  8153. +-    }
  8154. +-#endif /* CASEMOD_ATTRS */
  8155. +-  else if (value)
  8156. +-    {
  8157. +-      if (flags & ASS_APPEND)
  8158. +-      {
  8159. +-        oval = get_variable_value (var);
  8160. +-        if (oval == 0)        /* paranoia */
  8161. +-          oval = "";
  8162. +-        olen = STRLEN (oval);
  8163. +-        retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
  8164. +-        strcpy (retval, oval);
  8165. +-        if (value)
  8166. +-          strcpy (retval+olen, value);
  8167. +-      }
  8168. +-      else if (*value)
  8169. +-      retval = savestring (value);
  8170. +-      else
  8171. +-      {
  8172. +-        retval = (char *)xmalloc (1);
  8173. +-        retval[0] = '\0';
  8174. +-      }
  8175. +-    }
  8176. +-  else
  8177. +-    retval = (char *)NULL;
  8178. +-
  8179. +-  return retval;
  8180. +-}
  8181. +-
  8182. +-/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
  8183. +-   temporary environment (but usually is not). */
  8184. +-static SHELL_VAR *
  8185. +-bind_variable_internal (name, value, table, hflags, aflags)
  8186. +-     const char *name;
  8187. +-     char *value;
  8188. +-     HASH_TABLE *table;
  8189. +-     int hflags, aflags;
  8190. +-{
  8191. +-  char *newval;
  8192. +-  SHELL_VAR *entry;
  8193. +-
  8194. +-  entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
  8195. +-  /* Follow the nameref chain here if this is the global variables table */
  8196. +-  if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
  8197. +-    {
  8198. +-      entry = find_global_variable (entry->name);
  8199. +-      /* Let's see if we have a nameref referencing a variable that hasn't yet
  8200. +-       been created. */
  8201. +-      if (entry == 0)
  8202. +-      entry = find_variable_last_nameref (name);      /* XXX */
  8203. +-      if (entry == 0)                                 /* just in case */
  8204. +-        return (entry);
  8205. +-    }
  8206. +-
  8207. +-  /* The first clause handles `declare -n ref; ref=x;' */
  8208. +-  if (entry && invisible_p (entry) && nameref_p (entry))
  8209. +-    goto assign_value;
  8210. +-  else if (entry && nameref_p (entry))
  8211. +-    {
  8212. +-      newval = nameref_cell (entry);
  8213. +-#if defined (ARRAY_VARS)
  8214. +-      /* declare -n foo=x[2] */
  8215. +-      if (valid_array_reference (newval))
  8216. +-        /* XXX - should it be aflags? */
  8217. +-      entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
  8218. +-      else
  8219. +-#endif
  8220. +-      {
  8221. +-      entry = make_new_variable (newval, table);
  8222. +-      var_setvalue (entry, make_variable_value (entry, value, 0));
  8223. +-      }
  8224. +-    }
  8225. +-  else if (entry == 0)
  8226. +-    {
  8227. +-      entry = make_new_variable (name, table);
  8228. +-      var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
  8229. +-    }
  8230. +-  else if (entry->assign_func)        /* array vars have assign functions now */
  8231. +-    {
  8232. +-      INVALIDATE_EXPORTSTR (entry);
  8233. +-      newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
  8234. +-      if (assoc_p (entry))
  8235. +-      entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
  8236. +-      else if (array_p (entry))
  8237. +-      entry = (*(entry->assign_func)) (entry, newval, 0, 0);
  8238. +-      else
  8239. +-      entry = (*(entry->assign_func)) (entry, newval, -1, 0);
  8240. +-      if (newval != value)
  8241. +-      free (newval);
  8242. +-      return (entry);
  8243. +-    }
  8244. +-  else
  8245. +-    {
  8246. +-assign_value:
  8247. +-      if (readonly_p (entry) || noassign_p (entry))
  8248. +-      {
  8249. +-        if (readonly_p (entry))
  8250. +-          err_readonly (name);
  8251. +-        return (entry);
  8252. +-      }
  8253. +-
  8254. +-      /* Variables which are bound are visible. */
  8255. +-      VUNSETATTR (entry, att_invisible);
  8256. +-
  8257. +-#if defined (ARRAY_VARS)
  8258. +-      if (assoc_p (entry) || array_p (entry))
  8259. +-        newval = make_array_variable_value (entry, 0, "0", value, aflags);
  8260. +-      else
  8261. +-#endif
  8262. +-
  8263. +-      newval = make_variable_value (entry, value, aflags);    /* XXX */
  8264. +-
  8265. +-      /* Invalidate any cached export string */
  8266. +-      INVALIDATE_EXPORTSTR (entry);
  8267. +-
  8268. +-#if defined (ARRAY_VARS)
  8269. +-      /* XXX -- this bears looking at again -- XXX */
  8270. +-      /* If an existing array variable x is being assigned to with x=b or
  8271. +-       `read x' or something of that nature, silently convert it to
  8272. +-       x[0]=b or `read x[0]'. */
  8273. +-      if (assoc_p (entry))
  8274. +-      {
  8275. +-        assoc_insert (assoc_cell (entry), savestring ("0"), newval);
  8276. +-        free (newval);
  8277. +-      }
  8278. +-      else if (array_p (entry))
  8279. +-      {
  8280. +-        array_insert (array_cell (entry), 0, newval);
  8281. +-        free (newval);
  8282. +-      }
  8283. +-      else
  8284. +-#endif
  8285. +-      {
  8286. +-        FREE (value_cell (entry));
  8287. +-        var_setvalue (entry, newval);
  8288. +-      }
  8289. +-    }
  8290. +-
  8291. +-  if (mark_modified_vars)
  8292. +-    VSETATTR (entry, att_exported);
  8293. +-
  8294. +-  if (exported_p (entry))
  8295. +-    array_needs_making = 1;
  8296. +-
  8297. +-  return (entry);
  8298. +-}
  8299. +-     
  8300. +-/* Bind a variable NAME to VALUE.  This conses up the name
  8301. +-   and value strings.  If we have a temporary environment, we bind there
  8302. +-   first, then we bind into shell_variables. */
  8303. +-
  8304. +-SHELL_VAR *
  8305. +-bind_variable (name, value, flags)
  8306. +-     const char *name;
  8307. +-     char *value;
  8308. +-     int flags;
  8309. +-{
  8310. +-  SHELL_VAR *v, *nv;
  8311. +-  VAR_CONTEXT *vc, *nvc;
  8312. +-  int level;
  8313. +-
  8314. +-  if (shell_variables == 0)
  8315. +-    create_variable_tables ();
  8316. +-
  8317. +-  /* If we have a temporary environment, look there first for the variable,
  8318. +-     and, if found, modify the value there before modifying it in the
  8319. +-     shell_variables table.  This allows sourced scripts to modify values
  8320. +-     given to them in a temporary environment while modifying the variable
  8321. +-     value that the caller sees. */
  8322. +-  if (temporary_env)
  8323. +-    bind_tempenv_variable (name, value);
  8324. +-
  8325. +-  /* XXX -- handle local variables here. */
  8326. +-  for (vc = shell_variables; vc; vc = vc->down)
  8327. +-    {
  8328. +-      if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
  8329. +-      {
  8330. +-        v = hash_lookup (name, vc->table);
  8331. +-        nvc = vc;
  8332. +-        if (v && nameref_p (v))
  8333. +-          {
  8334. +-            nv = find_variable_nameref_context (v, vc, &nvc);
  8335. +-            if (nv == 0)
  8336. +-              {
  8337. +-                nv = find_variable_last_nameref_context (v, vc, &nvc);
  8338. +-                if (nv && nameref_p (nv))
  8339. +-                  {
  8340. +-                    /* If this nameref variable doesn't have a value yet,
  8341. +-                       set the value.  Otherwise, assign using the value as
  8342. +-                       normal. */
  8343. +-                    if (nameref_cell (nv) == 0)
  8344. +-                      return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
  8345. +-                    return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
  8346. +-                  }
  8347. +-                else
  8348. +-                  v = nv;
  8349. +-              }
  8350. +-            else
  8351. +-              v = nv;
  8352. +-          }
  8353. +-        if (v)
  8354. +-          return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
  8355. +-      }
  8356. +-    }
  8357. +-  /* bind_variable_internal will handle nameref resolution in this case */
  8358. +-  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
  8359. +-}
  8360. +-
  8361. +-SHELL_VAR *
  8362. +-bind_global_variable (name, value, flags)
  8363. +-     const char *name;
  8364. +-     char *value;
  8365. +-     int flags;
  8366. +-{
  8367. +-  SHELL_VAR *v, *nv;
  8368. +-  VAR_CONTEXT *vc, *nvc;
  8369. +-  int level;
  8370. +-
  8371. +-  if (shell_variables == 0)
  8372. +-    create_variable_tables ();
  8373. +-
  8374. +-  /* bind_variable_internal will handle nameref resolution in this case */
  8375. +-  return (bind_variable_internal (name, value, global_variables->table, 0, flags));
  8376. +-}
  8377. +-
  8378. +-/* Make VAR, a simple shell variable, have value VALUE.  Once assigned a
  8379. +-   value, variables are no longer invisible.  This is a duplicate of part
  8380. +-   of the internals of bind_variable.  If the variable is exported, or
  8381. +-   all modified variables should be exported, mark the variable for export
  8382. +-   and note that the export environment needs to be recreated. */
  8383. +-SHELL_VAR *
  8384. +-bind_variable_value (var, value, aflags)
  8385. +-     SHELL_VAR *var;
  8386. +-     char *value;
  8387. +-     int aflags;
  8388. +-{
  8389. +-  char *t;
  8390. +-  int invis;
  8391. +-
  8392. +-  invis = invisible_p (var);
  8393. +-  VUNSETATTR (var, att_invisible);
  8394. +-
  8395. +-  if (var->assign_func)
  8396. +-    {
  8397. +-      /* If we're appending, we need the old value, so use
  8398. +-       make_variable_value */
  8399. +-      t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
  8400. +-      (*(var->assign_func)) (var, t, -1, 0);
  8401. +-      if (t != value && t)
  8402. +-      free (t);      
  8403. +-    }
  8404. +-  else
  8405. +-    {
  8406. +-      t = make_variable_value (var, value, aflags);
  8407. +-#if defined (ARRAY_VARS)
  8408. +-      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
  8409. +-#else
  8410. +-      if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
  8411. +-#endif
  8412. +-      {
  8413. +-        free (t);
  8414. +-        if (invis)
  8415. +-          VSETATTR (var, att_invisible);      /* XXX */
  8416. +-        return ((SHELL_VAR *)NULL);
  8417. +-      }
  8418. +-      FREE (value_cell (var));
  8419. +-      var_setvalue (var, t);
  8420. +-    }
  8421. +-
  8422. +-  INVALIDATE_EXPORTSTR (var);
  8423. +-
  8424. +-  if (mark_modified_vars)
  8425. +-    VSETATTR (var, att_exported);
  8426. +-
  8427. +-  if (exported_p (var))
  8428. +-    array_needs_making = 1;
  8429. +-
  8430. +-  return (var);
  8431. +-}
  8432. +-
  8433. +-/* Bind/create a shell variable with the name LHS to the RHS.
  8434. +-   This creates or modifies a variable such that it is an integer.
  8435. +-
  8436. +-   This used to be in expr.c, but it is here so that all of the
  8437. +-   variable binding stuff is localized.  Since we don't want any
  8438. +-   recursive evaluation from bind_variable() (possible without this code,
  8439. +-   since bind_variable() calls the evaluator for variables with the integer
  8440. +-   attribute set), we temporarily turn off the integer attribute for each
  8441. +-   variable we set here, then turn it back on after binding as necessary. */
  8442. +-
  8443. +-SHELL_VAR *
  8444. +-bind_int_variable (lhs, rhs)
  8445. +-     char *lhs, *rhs;
  8446. +-{
  8447. +-  register SHELL_VAR *v;
  8448. +-  int isint, isarr, implicitarray;
  8449. +-
  8450. +-  isint = isarr = implicitarray = 0;
  8451. +-#if defined (ARRAY_VARS)
  8452. +-  if (valid_array_reference (lhs))
  8453. +-    {
  8454. +-      isarr = 1;
  8455. +-      v = array_variable_part (lhs, (char **)0, (int *)0);
  8456. +-    }
  8457. +-  else
  8458. +-#endif
  8459. +-    v = find_variable (lhs);
  8460. +-
  8461. +-  if (v)
  8462. +-    {
  8463. +-      isint = integer_p (v);
  8464. +-      VUNSETATTR (v, att_integer);
  8465. +-#if defined (ARRAY_VARS)
  8466. +-      if (array_p (v) && isarr == 0)
  8467. +-      implicitarray = 1;
  8468. +-#endif
  8469. +-    }
  8470. +-
  8471. +-#if defined (ARRAY_VARS)
  8472. +-  if (isarr)
  8473. +-    v = assign_array_element (lhs, rhs, 0);
  8474. +-  else if (implicitarray)
  8475. +-    v = bind_array_variable (lhs, 0, rhs, 0);
  8476. +-  else
  8477. +-#endif
  8478. +-    v = bind_variable (lhs, rhs, 0);
  8479. +-
  8480. +-  if (v && isint)
  8481. +-    VSETATTR (v, att_integer);
  8482. +-
  8483. +-  VUNSETATTR (v, att_invisible);
  8484. +-
  8485. +-  return (v);
  8486. +-}
  8487. +-
  8488. +-SHELL_VAR *
  8489. +-bind_var_to_int (var, val)
  8490. +-     char *var;
  8491. +-     intmax_t val;
  8492. +-{
  8493. +-  char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
  8494. +-
  8495. +-  p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
  8496. +-  return (bind_int_variable (var, p));
  8497. +-}
  8498. +-
  8499. +-/* Do a function binding to a variable.  You pass the name and
  8500. +-   the command to bind to.  This conses the name and command. */
  8501. +-SHELL_VAR *
  8502. +-bind_function (name, value)
  8503. +-     const char *name;
  8504. +-     COMMAND *value;
  8505. +-{
  8506. +-  SHELL_VAR *entry;
  8507. +-
  8508. +-  entry = find_function (name);
  8509. +-  if (entry == 0)
  8510. +-    {
  8511. +-      BUCKET_CONTENTS *elt;
  8512. +-
  8513. +-      elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
  8514. +-      entry = new_shell_variable (name);
  8515. +-      elt->data = (PTR_T)entry;
  8516. +-    }
  8517. +-  else
  8518. +-    INVALIDATE_EXPORTSTR (entry);
  8519. +-
  8520. +-  if (var_isset (entry))
  8521. +-    dispose_command (function_cell (entry));
  8522. +-
  8523. +-  if (value)
  8524. +-    var_setfunc (entry, copy_command (value));
  8525. +-  else
  8526. +-    var_setfunc (entry, 0);
  8527. +-
  8528. +-  VSETATTR (entry, att_function);
  8529. +-
  8530. +-  if (mark_modified_vars)
  8531. +-    VSETATTR (entry, att_exported);
  8532. +-
  8533. +-  VUNSETATTR (entry, att_invisible);          /* Just to be sure */
  8534. +-
  8535. +-  if (exported_p (entry))
  8536. +-    array_needs_making = 1;
  8537. +-
  8538. +-#if defined (PROGRAMMABLE_COMPLETION)
  8539. +-  set_itemlist_dirty (&it_functions);
  8540. +-#endif
  8541. +-
  8542. +-  return (entry);
  8543. +-}
  8544. +-
  8545. +-#if defined (DEBUGGER)
  8546. +-/* Bind a function definition, which includes source file and line number
  8547. +-   information in addition to the command, into the FUNCTION_DEF hash table.*/
  8548. +-void
  8549. +-bind_function_def (name, value)
  8550. +-     const char *name;
  8551. +-     FUNCTION_DEF *value;
  8552. +-{
  8553. +-  FUNCTION_DEF *entry;
  8554. +-  BUCKET_CONTENTS *elt;
  8555. +-  COMMAND *cmd;
  8556. +-
  8557. +-  entry = find_function_def (name);
  8558. +-  if (entry)
  8559. +-    {
  8560. +-      dispose_function_def_contents (entry);
  8561. +-      entry = copy_function_def_contents (value, entry);
  8562. +-    }
  8563. +-  else
  8564. +-    {
  8565. +-      cmd = value->command;
  8566. +-      value->command = 0;
  8567. +-      entry = copy_function_def (value);
  8568. +-      value->command = cmd;
  8569. +-
  8570. +-      elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
  8571. +-      elt->data = (PTR_T *)entry;
  8572. +-    }
  8573. +-}
  8574. +-#endif /* DEBUGGER */
  8575. +-
  8576. +-/* Add STRING, which is of the form foo=bar, to the temporary environment
  8577. +-   HASH_TABLE (temporary_env).  The functions in execute_cmd.c are
  8578. +-   responsible for moving the main temporary env to one of the other
  8579. +-   temporary environments.  The expansion code in subst.c calls this. */
  8580. +-int
  8581. +-assign_in_env (word, flags)
  8582. +-     WORD_DESC *word;
  8583. +-     int flags;
  8584. +-{
  8585. +-  int offset, aflags;
  8586. +-  char *name, *temp, *value;
  8587. +-  SHELL_VAR *var;
  8588. +-  const char *string;
  8589. +-
  8590. +-  string = word->word;
  8591. +-
  8592. +-  aflags = 0;
  8593. +-  offset = assignment (string, 0);
  8594. +-  name = savestring (string);
  8595. +-  value = (char *)NULL;
  8596. +-
  8597. +-  if (name[offset] == '=')
  8598. +-    {
  8599. +-      name[offset] = 0;
  8600. +-
  8601. +-      /* don't ignore the `+' when assigning temporary environment */
  8602. +-      if (name[offset - 1] == '+')
  8603. +-      {
  8604. +-        name[offset - 1] = '\0';
  8605. +-        aflags |= ASS_APPEND;
  8606. +-      }
  8607. +-
  8608. +-      var = find_variable (name);
  8609. +-      if (var && (readonly_p (var) || noassign_p (var)))
  8610. +-      {
  8611. +-        if (readonly_p (var))
  8612. +-          err_readonly (name);
  8613. +-        free (name);
  8614. +-        return (0);
  8615. +-      }
  8616. +-
  8617. +-      temp = name + offset + 1;
  8618. +-      value = expand_assignment_string_to_string (temp, 0);
  8619. +-
  8620. +-      if (var && (aflags & ASS_APPEND))
  8621. +-      {
  8622. +-        temp = make_variable_value (var, value, aflags);
  8623. +-        FREE (value);
  8624. +-        value = temp;
  8625. +-      }
  8626. +-    }
  8627. +-
  8628. +-  if (temporary_env == 0)
  8629. +-    temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
  8630. +-
  8631. +-  var = hash_lookup (name, temporary_env);
  8632. +-  if (var == 0)
  8633. +-    var = make_new_variable (name, temporary_env);
  8634. +-  else
  8635. +-    FREE (value_cell (var));
  8636. +-
  8637. +-  if (value == 0)
  8638. +-    {
  8639. +-      value = (char *)xmalloc (1);    /* like do_assignment_internal */
  8640. +-      value[0] = '\0';
  8641. +-    }
  8642. +-
  8643. +-  var_setvalue (var, value);
  8644. +-  var->attributes |= (att_exported|att_tempvar);
  8645. +-  var->context = variable_context;    /* XXX */
  8646. +-
  8647. +-  INVALIDATE_EXPORTSTR (var);
  8648. +-  var->exportstr = mk_env_string (name, value, 0);
  8649. +-
  8650. +-  array_needs_making = 1;
  8651. +-
  8652. +-  if (flags)
  8653. +-    stupidly_hack_special_variables (name);
  8654. +-
  8655. +-  if (echo_command_at_execute)
  8656. +-    /* The Korn shell prints the `+ ' in front of assignment statements,
  8657. +-      so we do too. */
  8658. +-    xtrace_print_assignment (name, value, 0, 1);
  8659. +-
  8660. +-  free (name);
  8661. +-  return 1;
  8662. +-}
  8663. +-
  8664. +-/* **************************************************************** */
  8665. +-/*                                                                */
  8666. +-/*                    Copying variables                           */
  8667. +-/*                                                                */
  8668. +-/* **************************************************************** */
  8669. +-
  8670. +-#ifdef INCLUDE_UNUSED
  8671. +-/* Copy VAR to a new data structure and return that structure. */
  8672. +-SHELL_VAR *
  8673. +-copy_variable (var)
  8674. +-     SHELL_VAR *var;
  8675. +-{
  8676. +-  SHELL_VAR *copy = (SHELL_VAR *)NULL;
  8677. +-
  8678. +-  if (var)
  8679. +-    {
  8680. +-      copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
  8681. +-
  8682. +-      copy->attributes = var->attributes;
  8683. +-      copy->name = savestring (var->name);
  8684. +-
  8685. +-      if (function_p (var))
  8686. +-      var_setfunc (copy, copy_command (function_cell (var)));
  8687. +-#if defined (ARRAY_VARS)
  8688. +-      else if (array_p (var))
  8689. +-      var_setarray (copy, array_copy (array_cell (var)));
  8690. +-      else if (assoc_p (var))
  8691. +-      var_setassoc (copy, assoc_copy (assoc_cell (var)));
  8692. +-#endif
  8693. +-      else if (nameref_cell (var))    /* XXX - nameref */
  8694. +-      var_setref (copy, savestring (nameref_cell (var)));
  8695. +-      else if (value_cell (var))      /* XXX - nameref */
  8696. +-      var_setvalue (copy, savestring (value_cell (var)));
  8697. +-      else
  8698. +-      var_setvalue (copy, (char *)NULL);
  8699. +-
  8700. +-      copy->dynamic_value = var->dynamic_value;
  8701. +-      copy->assign_func = var->assign_func;
  8702. +-
  8703. +-      copy->exportstr = COPY_EXPORTSTR (var);
  8704. +-
  8705. +-      copy->context = var->context;
  8706. +-    }
  8707. +-  return (copy);
  8708. +-}
  8709. +-#endif
  8710. +-
  8711. +-/* **************************************************************** */
  8712. +-/*                                                                */
  8713. +-/*              Deleting and unsetting variables                  */
  8714. +-/*                                                                */
  8715. +-/* **************************************************************** */
  8716. +-
  8717. +-/* Dispose of the information attached to VAR. */
  8718. +-static void
  8719. +-dispose_variable_value (var)
  8720. +-     SHELL_VAR *var;
  8721. +-{
  8722. +-  if (function_p (var))
  8723. +-    dispose_command (function_cell (var));
  8724. +-#if defined (ARRAY_VARS)
  8725. +-  else if (array_p (var))
  8726. +-    array_dispose (array_cell (var));
  8727. +-  else if (assoc_p (var))
  8728. +-    assoc_dispose (assoc_cell (var));
  8729. +-#endif
  8730. +-  else if (nameref_p (var))
  8731. +-    FREE (nameref_cell (var));
  8732. +-  else
  8733. +-    FREE (value_cell (var));
  8734. +-}
  8735. +-
  8736. +-void
  8737. +-dispose_variable (var)
  8738. +-     SHELL_VAR *var;
  8739. +-{
  8740. +-  if (var == 0)
  8741. +-    return;
  8742. +-
  8743. +-  if (nofree_p (var) == 0)
  8744. +-    dispose_variable_value (var);
  8745. +-
  8746. +-  FREE_EXPORTSTR (var);
  8747. +-
  8748. +-  free (var->name);
  8749. +-
  8750. +-  if (exported_p (var))
  8751. +-    array_needs_making = 1;
  8752. +-
  8753. +-  free (var);
  8754. +-}
  8755. +-
  8756. +-/* Unset the shell variable referenced by NAME.  Unsetting a nameref variable
  8757. +-   unsets the variable it resolves to but leaves the nameref alone. */
  8758. +-int
  8759. +-unbind_variable (name)
  8760. +-     const char *name;
  8761. +-{
  8762. +-  SHELL_VAR *v, *nv;
  8763. +-  int r;
  8764. +-
  8765. +-  v = var_lookup (name, shell_variables);
  8766. +-  nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
  8767. +-
  8768. +-  r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
  8769. +-  return r;
  8770. +-}
  8771. +-
  8772. +-/* Unbind NAME, where NAME is assumed to be a nameref variable */
  8773. +-int
  8774. +-unbind_nameref (name)
  8775. +-     const char *name;
  8776. +-{
  8777. +-  SHELL_VAR *v;
  8778. +-
  8779. +-  v = var_lookup (name, shell_variables);
  8780. +-  if (v && nameref_p (v))
  8781. +-    return makunbound (name, shell_variables);
  8782. +-  return 0;
  8783. +-}
  8784. +-
  8785. +-/* Unset the shell function named NAME. */
  8786. +-int
  8787. +-unbind_func (name)
  8788. +-     const char *name;
  8789. +-{
  8790. +-  BUCKET_CONTENTS *elt;
  8791. +-  SHELL_VAR *func;
  8792. +-
  8793. +-  elt = hash_remove (name, shell_functions, 0);
  8794. +-
  8795. +-  if (elt == 0)
  8796. +-    return -1;
  8797. +-
  8798. +-#if defined (PROGRAMMABLE_COMPLETION)
  8799. +-  set_itemlist_dirty (&it_functions);
  8800. +-#endif
  8801. +-
  8802. +-  func = (SHELL_VAR *)elt->data;
  8803. +-  if (func)
  8804. +-    {
  8805. +-      if (exported_p (func))
  8806. +-      array_needs_making++;
  8807. +-      dispose_variable (func);
  8808. +-    }
  8809. +-
  8810. +-  free (elt->key);
  8811. +-  free (elt);
  8812. +-
  8813. +-  return 0;  
  8814. +-}
  8815. +-
  8816. +-#if defined (DEBUGGER)
  8817. +-int
  8818. +-unbind_function_def (name)
  8819. +-     const char *name;
  8820. +-{
  8821. +-  BUCKET_CONTENTS *elt;
  8822. +-  FUNCTION_DEF *funcdef;
  8823. +-
  8824. +-  elt = hash_remove (name, shell_function_defs, 0);
  8825. +-
  8826. +-  if (elt == 0)
  8827. +-    return -1;
  8828. +-
  8829. +-  funcdef = (FUNCTION_DEF *)elt->data;
  8830. +-  if (funcdef)
  8831. +-    dispose_function_def (funcdef);
  8832. +-
  8833. +-  free (elt->key);
  8834. +-  free (elt);
  8835. +-
  8836. +-  return 0;  
  8837. +-}
  8838. +-#endif /* DEBUGGER */
  8839. +-
  8840. +-int
  8841. +-delete_var (name, vc)
  8842. +-     const char *name;
  8843. +-     VAR_CONTEXT *vc;
  8844. +-{
  8845. +-  BUCKET_CONTENTS *elt;
  8846. +-  SHELL_VAR *old_var;
  8847. +-  VAR_CONTEXT *v;
  8848. +-
  8849. +-  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
  8850. +-    if (elt = hash_remove (name, v->table, 0))
  8851. +-      break;
  8852. +-
  8853. +-  if (elt == 0)
  8854. +-    return (-1);
  8855. +-
  8856. +-  old_var = (SHELL_VAR *)elt->data;
  8857. +-  free (elt->key);
  8858. +-  free (elt);
  8859. +-
  8860. +-  dispose_variable (old_var);
  8861. +-  return (0);
  8862. +-}
  8863. +-
  8864. +-/* Make the variable associated with NAME go away.  HASH_LIST is the
  8865. +-   hash table from which this variable should be deleted (either
  8866. +-   shell_variables or shell_functions).
  8867. +-   Returns non-zero if the variable couldn't be found. */
  8868. +-int
  8869. +-makunbound (name, vc)
  8870. +-     const char *name;
  8871. +-     VAR_CONTEXT *vc;
  8872. +-{
  8873. +-  BUCKET_CONTENTS *elt, *new_elt;
  8874. +-  SHELL_VAR *old_var;
  8875. +-  VAR_CONTEXT *v;
  8876. +-  char *t;
  8877. +-
  8878. +-  for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
  8879. +-    if (elt = hash_remove (name, v->table, 0))
  8880. +-      break;
  8881. +-
  8882. +-  if (elt == 0)
  8883. +-    return (-1);
  8884. +-
  8885. +-  old_var = (SHELL_VAR *)elt->data;
  8886. +-
  8887. +-  if (old_var && exported_p (old_var))
  8888. +-    array_needs_making++;
  8889. +-
  8890. +-  /* If we're unsetting a local variable and we're still executing inside
  8891. +-     the function, just mark the variable as invisible.  The function
  8892. +-     eventually called by pop_var_context() will clean it up later.  This
  8893. +-     must be done so that if the variable is subsequently assigned a new
  8894. +-     value inside the function, the `local' attribute is still present.
  8895. +-     We also need to add it back into the correct hash table. */
  8896. +-  if (old_var && local_p (old_var) && variable_context == old_var->context)
  8897. +-    {
  8898. +-      if (nofree_p (old_var))
  8899. +-      var_setvalue (old_var, (char *)NULL);
  8900. +-#if defined (ARRAY_VARS)
  8901. +-      else if (array_p (old_var))
  8902. +-      array_dispose (array_cell (old_var));
  8903. +-      else if (assoc_p (old_var))
  8904. +-      assoc_dispose (assoc_cell (old_var));
  8905. +-#endif
  8906. +-      else if (nameref_p (old_var))
  8907. +-      FREE (nameref_cell (old_var));
  8908. +-      else
  8909. +-      FREE (value_cell (old_var));
  8910. +-      /* Reset the attributes.  Preserve the export attribute if the variable
  8911. +-       came from a temporary environment.  Make sure it stays local, and
  8912. +-       make it invisible. */
  8913. +-      old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
  8914. +-      VSETATTR (old_var, att_local);
  8915. +-      VSETATTR (old_var, att_invisible);
  8916. +-      var_setvalue (old_var, (char *)NULL);
  8917. +-      INVALIDATE_EXPORTSTR (old_var);
  8918. +-
  8919. +-      new_elt = hash_insert (savestring (old_var->name), v->table, 0);
  8920. +-      new_elt->data = (PTR_T)old_var;
  8921. +-      stupidly_hack_special_variables (old_var->name);
  8922. +-
  8923. +-      free (elt->key);
  8924. +-      free (elt);
  8925. +-      return (0);
  8926. +-    }
  8927. +-
  8928. +-  /* Have to save a copy of name here, because it might refer to
  8929. +-     old_var->name.  If so, stupidly_hack_special_variables will
  8930. +-     reference freed memory. */
  8931. +-  t = savestring (name);
  8932. +-
  8933. +-  free (elt->key);
  8934. +-  free (elt);
  8935. +-
  8936. +-  dispose_variable (old_var);
  8937. +-  stupidly_hack_special_variables (t);
  8938. +-  free (t);
  8939. +-
  8940. +-  return (0);
  8941. +-}
  8942. +-
  8943. +-/* Get rid of all of the variables in the current context. */
  8944. +-void
  8945. +-kill_all_local_variables ()
  8946. +-{
  8947. +-  VAR_CONTEXT *vc;
  8948. +-
  8949. +-  for (vc = shell_variables; vc; vc = vc->down)
  8950. +-    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  8951. +-      break;
  8952. +-  if (vc == 0)
  8953. +-    return;           /* XXX */
  8954. +-
  8955. +-  if (vc->table && vc_haslocals (vc))
  8956. +-    {
  8957. +-      delete_all_variables (vc->table);
  8958. +-      hash_dispose (vc->table);
  8959. +-    }
  8960. +-  vc->table = (HASH_TABLE *)NULL;
  8961. +-}
  8962. +-
  8963. +-static void
  8964. +-free_variable_hash_data (data)
  8965. +-     PTR_T data;
  8966. +-{
  8967. +-  SHELL_VAR *var;
  8968. +-
  8969. +-  var = (SHELL_VAR *)data;
  8970. +-  dispose_variable (var);
  8971. +-}
  8972. +-
  8973. +-/* Delete the entire contents of the hash table. */
  8974. +-void
  8975. +-delete_all_variables (hashed_vars)
  8976. +-     HASH_TABLE *hashed_vars;
  8977. +-{
  8978. +-  hash_flush (hashed_vars, free_variable_hash_data);
  8979. +-}
  8980. +-
  8981. +-/* **************************************************************** */
  8982. +-/*                                                                */
  8983. +-/*                 Setting variable attributes                    */
  8984. +-/*                                                                */
  8985. +-/* **************************************************************** */
  8986. +-
  8987. +-#define FIND_OR_MAKE_VARIABLE(name, entry) \
  8988. +-  do \
  8989. +-    { \
  8990. +-      entry = find_variable (name); \
  8991. +-      if (!entry) \
  8992. +-      { \
  8993. +-        entry = bind_variable (name, "", 0); \
  8994. +-        if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
  8995. +-      } \
  8996. +-    } \
  8997. +-  while (0)
  8998. +-
  8999. +-/* Make the variable associated with NAME be readonly.
  9000. +-   If NAME does not exist yet, create it. */
  9001. +-void
  9002. +-set_var_read_only (name)
  9003. +-     char *name;
  9004. +-{
  9005. +-  SHELL_VAR *entry;
  9006. +-
  9007. +-  FIND_OR_MAKE_VARIABLE (name, entry);
  9008. +-  VSETATTR (entry, att_readonly);
  9009. +-}
  9010. +-
  9011. +-#ifdef INCLUDE_UNUSED
  9012. +-/* Make the function associated with NAME be readonly.
  9013. +-   If NAME does not exist, we just punt, like auto_export code below. */
  9014. +-void
  9015. +-set_func_read_only (name)
  9016. +-     const char *name;
  9017. +-{
  9018. +-  SHELL_VAR *entry;
  9019. +-
  9020. +-  entry = find_function (name);
  9021. +-  if (entry)
  9022. +-    VSETATTR (entry, att_readonly);
  9023. +-}
  9024. +-
  9025. +-/* Make the variable associated with NAME be auto-exported.
  9026. +-   If NAME does not exist yet, create it. */
  9027. +-void
  9028. +-set_var_auto_export (name)
  9029. +-     char *name;
  9030. +-{
  9031. +-  SHELL_VAR *entry;
  9032. +-
  9033. +-  FIND_OR_MAKE_VARIABLE (name, entry);
  9034. +-  set_auto_export (entry);
  9035. +-}
  9036. +-
  9037. +-/* Make the function associated with NAME be auto-exported. */
  9038. +-void
  9039. +-set_func_auto_export (name)
  9040. +-     const char *name;
  9041. +-{
  9042. +-  SHELL_VAR *entry;
  9043. +-
  9044. +-  entry = find_function (name);
  9045. +-  if (entry)
  9046. +-    set_auto_export (entry);
  9047. +-}
  9048. +-#endif
  9049. +-
  9050. +-/* **************************************************************** */
  9051. +-/*                                                                */
  9052. +-/*                 Creating lists of variables                    */
  9053. +-/*                                                                */
  9054. +-/* **************************************************************** */
  9055. +-
  9056. +-static VARLIST *
  9057. +-vlist_alloc (nentries)
  9058. +-     int nentries;
  9059. +-{
  9060. +-  VARLIST  *vlist;
  9061. +-
  9062. +-  vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
  9063. +-  vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
  9064. +-  vlist->list_size = nentries;
  9065. +-  vlist->list_len = 0;
  9066. +-  vlist->list[0] = (SHELL_VAR *)NULL;
  9067. +-
  9068. +-  return vlist;
  9069. +-}
  9070. +-
  9071. +-static VARLIST *
  9072. +-vlist_realloc (vlist, n)
  9073. +-     VARLIST *vlist;
  9074. +-     int n;
  9075. +-{
  9076. +-  if (vlist == 0)
  9077. +-    return (vlist = vlist_alloc (n));
  9078. +-  if (n > vlist->list_size)
  9079. +-    {
  9080. +-      vlist->list_size = n;
  9081. +-      vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
  9082. +-    }
  9083. +-  return vlist;
  9084. +-}
  9085. +-
  9086. +-static void
  9087. +-vlist_add (vlist, var, flags)
  9088. +-     VARLIST *vlist;
  9089. +-     SHELL_VAR *var;
  9090. +-     int flags;
  9091. +-{
  9092. +-  register int i;
  9093. +-
  9094. +-  for (i = 0; i < vlist->list_len; i++)
  9095. +-    if (STREQ (var->name, vlist->list[i]->name))
  9096. +-      break;
  9097. +-  if (i < vlist->list_len)
  9098. +-    return;
  9099. +-
  9100. +-  if (i >= vlist->list_size)
  9101. +-    vlist = vlist_realloc (vlist, vlist->list_size + 16);
  9102. +-
  9103. +-  vlist->list[vlist->list_len++] = var;
  9104. +-  vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
  9105. +-}
  9106. +-
  9107. +-/* Map FUNCTION over the variables in VAR_HASH_TABLE.  Return an array of the
  9108. +-   variables for which FUNCTION returns a non-zero value.  A NULL value
  9109. +-   for FUNCTION means to use all variables. */
  9110. +-SHELL_VAR **
  9111. +-map_over (function, vc)
  9112. +-     sh_var_map_func_t *function;
  9113. +-     VAR_CONTEXT *vc;
  9114. +-{
  9115. +-  VAR_CONTEXT *v;
  9116. +-  VARLIST *vlist;
  9117. +-  SHELL_VAR **ret;
  9118. +-  int nentries;
  9119. +-
  9120. +-  for (nentries = 0, v = vc; v; v = v->down)
  9121. +-    nentries += HASH_ENTRIES (v->table);
  9122. +-
  9123. +-  if (nentries == 0)
  9124. +-    return (SHELL_VAR **)NULL;
  9125. +-
  9126. +-  vlist = vlist_alloc (nentries);
  9127. +-
  9128. +-  for (v = vc; v; v = v->down)
  9129. +-    flatten (v->table, function, vlist, 0);
  9130. +-
  9131. +-  ret = vlist->list;
  9132. +-  free (vlist);
  9133. +-  return ret;
  9134. +-}
  9135. +-
  9136. +-SHELL_VAR **
  9137. +-map_over_funcs (function)
  9138. +-     sh_var_map_func_t *function;
  9139. +-{
  9140. +-  VARLIST *vlist;
  9141. +-  SHELL_VAR **ret;
  9142. +-
  9143. +-  if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
  9144. +-    return ((SHELL_VAR **)NULL);
  9145. +-
  9146. +-  vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
  9147. +-
  9148. +-  flatten (shell_functions, function, vlist, 0);
  9149. +-
  9150. +-  ret = vlist->list;
  9151. +-  free (vlist);
  9152. +-  return ret;
  9153. +-}
  9154. +-
  9155. +-/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
  9156. +-   elements for which FUNC succeeds to VLIST->list.  FLAGS is reserved
  9157. +-   for future use.  Only unique names are added to VLIST.  If FUNC is
  9158. +-   NULL, each variable in VAR_HASH_TABLE is added to VLIST.  If VLIST is
  9159. +-   NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE.  If VLIST
  9160. +-   and FUNC are both NULL, nothing happens. */
  9161. +-static void
  9162. +-flatten (var_hash_table, func, vlist, flags)
  9163. +-     HASH_TABLE *var_hash_table;
  9164. +-     sh_var_map_func_t *func;
  9165. +-     VARLIST *vlist;
  9166. +-     int flags;
  9167. +-{
  9168. +-  register int i;
  9169. +-  register BUCKET_CONTENTS *tlist;
  9170. +-  int r;
  9171. +-  SHELL_VAR *var;
  9172. +-
  9173. +-  if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
  9174. +-    return;
  9175. +-
  9176. +-  for (i = 0; i < var_hash_table->nbuckets; i++)
  9177. +-    {
  9178. +-      for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
  9179. +-      {
  9180. +-        var = (SHELL_VAR *)tlist->data;
  9181. +-
  9182. +-        r = func ? (*func) (var) : 1;
  9183. +-        if (r && vlist)
  9184. +-          vlist_add (vlist, var, flags);
  9185. +-      }
  9186. +-    }
  9187. +-}
  9188. +-
  9189. +-void
  9190. +-sort_variables (array)
  9191. +-     SHELL_VAR **array;
  9192. +-{
  9193. +-  qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
  9194. +-}
  9195. +-
  9196. +-static int
  9197. +-qsort_var_comp (var1, var2)
  9198. +-     SHELL_VAR **var1, **var2;
  9199. +-{
  9200. +-  int result;
  9201. +-
  9202. +-  if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
  9203. +-    result = strcmp ((*var1)->name, (*var2)->name);
  9204. +-
  9205. +-  return (result);
  9206. +-}
  9207. +-
  9208. +-/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
  9209. +-   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
  9210. +-static SHELL_VAR **
  9211. +-vapply (func)
  9212. +-     sh_var_map_func_t *func;
  9213. +-{
  9214. +-  SHELL_VAR **list;
  9215. +-
  9216. +-  list = map_over (func, shell_variables);
  9217. +-  if (list /* && posixly_correct */)
  9218. +-    sort_variables (list);
  9219. +-  return (list);
  9220. +-}
  9221. +-
  9222. +-/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
  9223. +-   which FUNC succeeds to an array of SHELL_VAR *s.  Returns the array. */
  9224. +-static SHELL_VAR **
  9225. +-fapply (func)
  9226. +-     sh_var_map_func_t *func;
  9227. +-{
  9228. +-  SHELL_VAR **list;
  9229. +-
  9230. +-  list = map_over_funcs (func);
  9231. +-  if (list /* && posixly_correct */)
  9232. +-    sort_variables (list);
  9233. +-  return (list);
  9234. +-}
  9235. +-
  9236. +-/* Create a NULL terminated array of all the shell variables. */
  9237. +-SHELL_VAR **
  9238. +-all_shell_variables ()
  9239. +-{
  9240. +-  return (vapply ((sh_var_map_func_t *)NULL));
  9241. +-}
  9242. +-
  9243. +-/* Create a NULL terminated array of all the shell functions. */
  9244. +-SHELL_VAR **
  9245. +-all_shell_functions ()
  9246. +-{
  9247. +-  return (fapply ((sh_var_map_func_t *)NULL));
  9248. +-}
  9249. +-
  9250. +-static int
  9251. +-visible_var (var)
  9252. +-     SHELL_VAR *var;
  9253. +-{
  9254. +-  return (invisible_p (var) == 0);
  9255. +-}
  9256. +-
  9257. +-SHELL_VAR **
  9258. +-all_visible_functions ()
  9259. +-{
  9260. +-  return (fapply (visible_var));
  9261. +-}
  9262. +-
  9263. +-SHELL_VAR **
  9264. +-all_visible_variables ()
  9265. +-{
  9266. +-  return (vapply (visible_var));
  9267. +-}
  9268. +-
  9269. +-/* Return non-zero if the variable VAR is visible and exported.  Array
  9270. +-   variables cannot be exported. */
  9271. +-static int
  9272. +-visible_and_exported (var)
  9273. +-     SHELL_VAR *var;
  9274. +-{
  9275. +-  return (invisible_p (var) == 0 && exported_p (var));
  9276. +-}
  9277. +-
  9278. +-/* Candidate variables for the export environment are either valid variables
  9279. +-   with the export attribute or invalid variables inherited from the initial
  9280. +-   environment and simply passed through. */
  9281. +-static int
  9282. +-export_environment_candidate (var)
  9283. +-     SHELL_VAR *var;
  9284. +-{
  9285. +-  return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
  9286. +-}
  9287. +-
  9288. +-/* Return non-zero if VAR is a local variable in the current context and
  9289. +-   is exported. */
  9290. +-static int
  9291. +-local_and_exported (var)
  9292. +-     SHELL_VAR *var;
  9293. +-{
  9294. +-  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
  9295. +-}
  9296. +-
  9297. +-SHELL_VAR **
  9298. +-all_exported_variables ()
  9299. +-{
  9300. +-  return (vapply (visible_and_exported));
  9301. +-}
  9302. +-
  9303. +-SHELL_VAR **
  9304. +-local_exported_variables ()
  9305. +-{
  9306. +-  return (vapply (local_and_exported));
  9307. +-}
  9308. +-
  9309. +-static int
  9310. +-variable_in_context (var)
  9311. +-     SHELL_VAR *var;
  9312. +-{
  9313. +-  return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
  9314. +-}
  9315. +-
  9316. +-SHELL_VAR **
  9317. +-all_local_variables ()
  9318. +-{
  9319. +-  VARLIST *vlist;
  9320. +-  SHELL_VAR **ret;
  9321. +-  VAR_CONTEXT *vc;
  9322. +-
  9323. +-  vc = shell_variables;
  9324. +-  for (vc = shell_variables; vc; vc = vc->down)
  9325. +-    if (vc_isfuncenv (vc) && vc->scope == variable_context)
  9326. +-      break;
  9327. +-
  9328. +-  if (vc == 0)
  9329. +-    {
  9330. +-      internal_error (_("all_local_variables: no function context at current scope"));
  9331. +-      return (SHELL_VAR **)NULL;
  9332. +-    }
  9333. +-  if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
  9334. +-    return (SHELL_VAR **)NULL;
  9335. +-    
  9336. +-  vlist = vlist_alloc (HASH_ENTRIES (vc->table));
  9337. +-
  9338. +-  flatten (vc->table, variable_in_context, vlist, 0);
  9339. +-
  9340. +-  ret = vlist->list;
  9341. +-  free (vlist);
  9342. +-  if (ret)
  9343. +-    sort_variables (ret);
  9344. +-  return ret;
  9345. +-}
  9346. +-
  9347. +-#if defined (ARRAY_VARS)
  9348. +-/* Return non-zero if the variable VAR is visible and an array. */
  9349. +-static int
  9350. +-visible_array_vars (var)
  9351. +-     SHELL_VAR *var;
  9352. +-{
  9353. +-  return (invisible_p (var) == 0 && array_p (var));
  9354. +-}
  9355. +-
  9356. +-SHELL_VAR **
  9357. +-all_array_variables ()
  9358. +-{
  9359. +-  return (vapply (visible_array_vars));
  9360. +-}
  9361. +-#endif /* ARRAY_VARS */
  9362. +-
  9363. +-char **
  9364. +-all_variables_matching_prefix (prefix)
  9365. +-     const char *prefix;
  9366. +-{
  9367. +-  SHELL_VAR **varlist;
  9368. +-  char **rlist;
  9369. +-  int vind, rind, plen;
  9370. +-
  9371. +-  plen = STRLEN (prefix);
  9372. +-  varlist = all_visible_variables ();
  9373. +-  for (vind = 0; varlist && varlist[vind]; vind++)
  9374. +-    ;
  9375. +-  if (varlist == 0 || vind == 0)
  9376. +-    return ((char **)NULL);
  9377. +-  rlist = strvec_create (vind + 1);
  9378. +-  for (vind = rind = 0; varlist[vind]; vind++)
  9379. +-    {
  9380. +-      if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
  9381. +-      rlist[rind++] = savestring (varlist[vind]->name);
  9382. +-    }
  9383. +-  rlist[rind] = (char *)0;
  9384. +-  free (varlist);
  9385. +-
  9386. +-  return rlist;
  9387. +-}
  9388. +-
  9389. +-/* **************************************************************** */
  9390. +-/*                                                                */
  9391. +-/*             Managing temporary variable scopes                 */
  9392. +-/*                                                                */
  9393. +-/* **************************************************************** */
  9394. +-
  9395. +-/* Make variable NAME have VALUE in the temporary environment. */
  9396. +-static SHELL_VAR *
  9397. +-bind_tempenv_variable (name, value)
  9398. +-     const char *name;
  9399. +-     char *value;
  9400. +-{
  9401. +-  SHELL_VAR *var;
  9402. +-
  9403. +-  var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
  9404. +-
  9405. +-  if (var)
  9406. +-    {
  9407. +-      FREE (value_cell (var));
  9408. +-      var_setvalue (var, savestring (value));
  9409. +-      INVALIDATE_EXPORTSTR (var);
  9410. +-    }
  9411. +-
  9412. +-  return (var);
  9413. +-}
  9414. +-
  9415. +-/* Find a variable in the temporary environment that is named NAME.
  9416. +-   Return the SHELL_VAR *, or NULL if not found. */
  9417. +-SHELL_VAR *
  9418. +-find_tempenv_variable (name)
  9419. +-     const char *name;
  9420. +-{
  9421. +-  return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
  9422. +-}
  9423. +-
  9424. +-char **tempvar_list;
  9425. +-int tvlist_ind;
  9426. +-
  9427. +-/* Push the variable described by (SHELL_VAR *)DATA down to the next
  9428. +-   variable context from the temporary environment. */
  9429. +-static void
  9430. +-push_temp_var (data)
  9431. +-     PTR_T data;
  9432. +-{
  9433. +-  SHELL_VAR *var, *v;
  9434. +-  HASH_TABLE *binding_table;
  9435. +-
  9436. +-  var = (SHELL_VAR *)data;
  9437. +-
  9438. +-  binding_table = shell_variables->table;
  9439. +-  if (binding_table == 0)
  9440. +-    {
  9441. +-      if (shell_variables == global_variables)
  9442. +-      /* shouldn't happen */
  9443. +-      binding_table = shell_variables->table = global_variables->table = hash_create (0);
  9444. +-      else
  9445. +-      binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
  9446. +-    }
  9447. +-
  9448. +-  v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
  9449. +-
  9450. +-  /* XXX - should we set the context here?  It shouldn't matter because of how
  9451. +-     assign_in_env works, but might want to check. */
  9452. +-  if (binding_table == global_variables->table)               /* XXX */
  9453. +-    var->attributes &= ~(att_tempvar|att_propagate);
  9454. +-  else
  9455. +-    {
  9456. +-      var->attributes |= att_propagate;
  9457. +-      if  (binding_table == shell_variables->table)
  9458. +-      shell_variables->flags |= VC_HASTMPVAR;
  9459. +-    }
  9460. +-  v->attributes |= var->attributes;
  9461. +-
  9462. +-  if (find_special_var (var->name) >= 0)
  9463. +-    tempvar_list[tvlist_ind++] = savestring (var->name);
  9464. +-
  9465. +-  dispose_variable (var);
  9466. +-}
  9467. +-
  9468. +-static void
  9469. +-propagate_temp_var (data)
  9470. +-     PTR_T data;
  9471. +-{
  9472. +-  SHELL_VAR *var;
  9473. +-
  9474. +-  var = (SHELL_VAR *)data;
  9475. +-  if (tempvar_p (var) && (var->attributes & att_propagate))
  9476. +-    push_temp_var (data);
  9477. +-  else
  9478. +-    {
  9479. +-      if (find_special_var (var->name) >= 0)
  9480. +-      tempvar_list[tvlist_ind++] = savestring (var->name);
  9481. +-      dispose_variable (var);
  9482. +-    }
  9483. +-}
  9484. +-
  9485. +-/* Free the storage used in the hash table for temporary
  9486. +-   environment variables.  PUSHF is a function to be called
  9487. +-   to free each hash table entry.  It takes care of pushing variables
  9488. +-   to previous scopes if appropriate.  PUSHF stores names of variables
  9489. +-   that require special handling (e.g., IFS) on tempvar_list, so this
  9490. +-   function can call stupidly_hack_special_variables on all the
  9491. +-   variables in the list when the temporary hash table is destroyed. */
  9492. +-static void
  9493. +-dispose_temporary_env (pushf)
  9494. +-     sh_free_func_t *pushf;
  9495. +-{
  9496. +-  int i;
  9497. +-
  9498. +-  tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
  9499. +-  tempvar_list[tvlist_ind = 0] = 0;
  9500. +-    
  9501. +-  hash_flush (temporary_env, pushf);
  9502. +-  hash_dispose (temporary_env);
  9503. +-  temporary_env = (HASH_TABLE *)NULL;
  9504. +-
  9505. +-  tempvar_list[tvlist_ind] = 0;
  9506. +-
  9507. +-  array_needs_making = 1;
  9508. +-
  9509. +-#if 0
  9510. +-  sv_ifs ("IFS");             /* XXX here for now -- check setifs in assign_in_env */  
  9511. +-#endif
  9512. +-  for (i = 0; i < tvlist_ind; i++)
  9513. +-    stupidly_hack_special_variables (tempvar_list[i]);
  9514. +-
  9515. +-  strvec_dispose (tempvar_list);
  9516. +-  tempvar_list = 0;
  9517. +-  tvlist_ind = 0;
  9518. +-}
  9519. +-
  9520. +-void
  9521. +-dispose_used_env_vars ()
  9522. +-{
  9523. +-  if (temporary_env)
  9524. +-    {
  9525. +-      dispose_temporary_env (propagate_temp_var);
  9526. +-      maybe_make_export_env ();
  9527. +-    }
  9528. +-}
  9529. +-
  9530. +-/* Take all of the shell variables in the temporary environment HASH_TABLE
  9531. +-   and make shell variables from them at the current variable context. */
  9532. +-void
  9533. +-merge_temporary_env ()
  9534. +-{
  9535. +-  if (temporary_env)
  9536. +-    dispose_temporary_env (push_temp_var);
  9537. +-}
  9538. +-
  9539. +-/* **************************************************************** */
  9540. +-/*                                                                */
  9541. +-/*         Creating and manipulating the environment              */
  9542. +-/*                                                                */
  9543. +-/* **************************************************************** */
  9544. +-
  9545. +-static inline char *
  9546. +-mk_env_string (name, value, isfunc)
  9547. +-     const char *name, *value;
  9548. +-     int isfunc;
  9549. +-{
  9550. +-  size_t name_len, value_len;
  9551. +-  char        *p, *q;
  9552. +-
  9553. +-  name_len = strlen (name);
  9554. +-  value_len = STRLEN (value);
  9555. +-
  9556. +-  /* If we are exporting a shell function, construct the encoded function
  9557. +-     name. */
  9558. +-  if (isfunc && value)
  9559. +-    {
  9560. +-      p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
  9561. +-      q = p;
  9562. +-      memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
  9563. +-      q += BASHFUNC_PREFLEN;
  9564. +-      memcpy (q, name, name_len);
  9565. +-      q += name_len;
  9566. +-      memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
  9567. +-      q += BASHFUNC_SUFFLEN;
  9568. +-    }
  9569. +-  else
  9570. +-    {
  9571. +-      p = (char *)xmalloc (2 + name_len + value_len);
  9572. +-      memcpy (p, name, name_len);
  9573. +-      q = p + name_len;
  9574. +-    }
  9575. +-
  9576. +-  q[0] = '=';
  9577. +-  if (value && *value)
  9578. +-    memcpy (q + 1, value, value_len + 1);
  9579. +-  else
  9580. +-    q[1] = '\0';
  9581. +-
  9582. +-  return (p);
  9583. +-}
  9584. +-
  9585. +-#ifdef DEBUG
  9586. +-/* Debugging */
  9587. +-static int
  9588. +-valid_exportstr (v)
  9589. +-     SHELL_VAR *v;
  9590. +-{
  9591. +-  char *s;
  9592. +-
  9593. +-  s = v->exportstr;
  9594. +-  if (s == 0)
  9595. +-    {
  9596. +-      internal_error (_("%s has null exportstr"), v->name);
  9597. +-      return (0);
  9598. +-    }
  9599. +-  if (legal_variable_starter ((unsigned char)*s) == 0)
  9600. +-    {
  9601. +-      internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
  9602. +-      return (0);
  9603. +-    }
  9604. +-  for (s = v->exportstr + 1; s && *s; s++)
  9605. +-    {
  9606. +-      if (*s == '=')
  9607. +-      break;
  9608. +-      if (legal_variable_char ((unsigned char)*s) == 0)
  9609. +-      {
  9610. +-        internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
  9611. +-        return (0);
  9612. +-      }
  9613. +-    }
  9614. +-  if (*s != '=')
  9615. +-    {
  9616. +-      internal_error (_("no `=' in exportstr for %s"), v->name);
  9617. +-      return (0);
  9618. +-    }
  9619. +-  return (1);
  9620. +-}
  9621. +-#endif
  9622. +-
  9623. +-static char **
  9624. +-make_env_array_from_var_list (vars)
  9625. +-     SHELL_VAR **vars;
  9626. +-{
  9627. +-  register int i, list_index;
  9628. +-  register SHELL_VAR *var;
  9629. +-  char **list, *value;
  9630. +-
  9631. +-  list = strvec_create ((1 + strvec_len ((char **)vars)));
  9632. +-
  9633. +-#define USE_EXPORTSTR (value == var->exportstr)
  9634. +-
  9635. +-  for (i = 0, list_index = 0; var = vars[i]; i++)
  9636. +-    {
  9637. +-#if defined (__CYGWIN__)
  9638. +-      /* We don't use the exportstr stuff on Cygwin at all. */
  9639. +-      INVALIDATE_EXPORTSTR (var);
  9640. +-#endif
  9641. +-      if (var->exportstr)
  9642. +-      value = var->exportstr;
  9643. +-      else if (function_p (var))
  9644. +-      value = named_function_string ((char *)NULL, function_cell (var), 0);
  9645. +-#if defined (ARRAY_VARS)
  9646. +-      else if (array_p (var))
  9647. +-#  if ARRAY_EXPORT
  9648. +-      value = array_to_assignment_string (array_cell (var));
  9649. +-#  else
  9650. +-      continue;       /* XXX array vars cannot yet be exported */
  9651. +-#  endif /* ARRAY_EXPORT */
  9652. +-      else if (assoc_p (var))
  9653. +-#  if 0
  9654. +-      value = assoc_to_assignment_string (assoc_cell (var));
  9655. +-#  else
  9656. +-      continue;       /* XXX associative array vars cannot yet be exported */
  9657. +-#  endif
  9658. +-#endif
  9659. +-      else
  9660. +-      value = value_cell (var);
  9661. +-
  9662. +-      if (value)
  9663. +-      {
  9664. +-        /* Gee, I'd like to get away with not using savestring() if we're
  9665. +-           using the cached exportstr... */
  9666. +-        list[list_index] = USE_EXPORTSTR ? savestring (value)
  9667. +-                                         : mk_env_string (var->name, value, function_p (var));
  9668. +-
  9669. +-        if (USE_EXPORTSTR == 0)
  9670. +-          SAVE_EXPORTSTR (var, list[list_index]);
  9671. +-
  9672. +-        list_index++;
  9673. +-#undef USE_EXPORTSTR
  9674. +-
  9675. +-#if 0 /* not yet */
  9676. +-#if defined (ARRAY_VARS)
  9677. +-        if (array_p (var) || assoc_p (var))
  9678. +-          free (value);
  9679. +-#endif
  9680. +-#endif
  9681. +-      }
  9682. +-    }
  9683. +-
  9684. +-  list[list_index] = (char *)NULL;
  9685. +-  return (list);
  9686. +-}
  9687. +-
  9688. +-/* Make an array of assignment statements from the hash table
  9689. +-   HASHED_VARS which contains SHELL_VARs.  Only visible, exported
  9690. +-   variables are eligible. */
  9691. +-static char **
  9692. +-make_var_export_array (vcxt)
  9693. +-     VAR_CONTEXT *vcxt;
  9694. +-{
  9695. +-  char **list;
  9696. +-  SHELL_VAR **vars;
  9697. +-
  9698. +-#if 0
  9699. +-  vars = map_over (visible_and_exported, vcxt);
  9700. +-#else
  9701. +-  vars = map_over (export_environment_candidate, vcxt);
  9702. +-#endif
  9703. +-
  9704. +-  if (vars == 0)
  9705. +-    return (char **)NULL;
  9706. +-
  9707. +-  list = make_env_array_from_var_list (vars);
  9708. +-
  9709. +-  free (vars);
  9710. +-  return (list);
  9711. +-}
  9712. +-
  9713. +-static char **
  9714. +-make_func_export_array ()
  9715. +-{
  9716. +-  char **list;
  9717. +-  SHELL_VAR **vars;
  9718. +-
  9719. +-  vars = map_over_funcs (visible_and_exported);
  9720. +-  if (vars == 0)
  9721. +-    return (char **)NULL;
  9722. +-
  9723. +-  list = make_env_array_from_var_list (vars);
  9724. +-
  9725. +-  free (vars);
  9726. +-  return (list);
  9727. +-}
  9728. +-
  9729. +-/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
  9730. +-#define add_to_export_env(envstr,do_alloc) \
  9731. +-do \
  9732. +-  { \
  9733. +-    if (export_env_index >= (export_env_size - 1)) \
  9734. +-      { \
  9735. +-      export_env_size += 16; \
  9736. +-      export_env = strvec_resize (export_env, export_env_size); \
  9737. +-      environ = export_env; \
  9738. +-      } \
  9739. +-    export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
  9740. +-    export_env[export_env_index] = (char *)NULL; \
  9741. +-  } while (0)
  9742. +-
  9743. +-/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
  9744. +-   array with the same left-hand side.  Return the new EXPORT_ENV. */
  9745. +-char **
  9746. +-add_or_supercede_exported_var (assign, do_alloc)
  9747. +-     char *assign;
  9748. +-     int do_alloc;
  9749. +-{
  9750. +-  register int i;
  9751. +-  int equal_offset;
  9752. +-
  9753. +-  equal_offset = assignment (assign, 0);
  9754. +-  if (equal_offset == 0)
  9755. +-    return (export_env);
  9756. +-
  9757. +-  /* If this is a function, then only supersede the function definition.
  9758. +-     We do this by including the `=() {' in the comparison, like
  9759. +-     initialize_shell_variables does. */
  9760. +-  if (assign[equal_offset + 1] == '(' &&
  9761. +-     strncmp (assign + equal_offset + 2, ") {", 3) == 0)              /* } */
  9762. +-    equal_offset += 4;
  9763. +-
  9764. +-  for (i = 0; i < export_env_index; i++)
  9765. +-    {
  9766. +-      if (STREQN (assign, export_env[i], equal_offset + 1))
  9767. +-      {
  9768. +-        free (export_env[i]);
  9769. +-        export_env[i] = do_alloc ? savestring (assign) : assign;
  9770. +-        return (export_env);
  9771. +-      }
  9772. +-    }
  9773. +-  add_to_export_env (assign, do_alloc);
  9774. +-  return (export_env);
  9775. +-}
  9776. +-
  9777. +-static void
  9778. +-add_temp_array_to_env (temp_array, do_alloc, do_supercede)
  9779. +-     char **temp_array;
  9780. +-     int do_alloc, do_supercede;
  9781. +-{
  9782. +-  register int i;
  9783. +-
  9784. +-  if (temp_array == 0)
  9785. +-    return;
  9786. +-
  9787. +-  for (i = 0; temp_array[i]; i++)
  9788. +-    {
  9789. +-      if (do_supercede)
  9790. +-      export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
  9791. +-      else
  9792. +-      add_to_export_env (temp_array[i], do_alloc);
  9793. +-    }
  9794. +-
  9795. +-  free (temp_array);
  9796. +-}
  9797. +-
  9798. +-/* Make the environment array for the command about to be executed, if the
  9799. +-   array needs making.  Otherwise, do nothing.  If a shell action could
  9800. +-   change the array that commands receive for their environment, then the
  9801. +-   code should `array_needs_making++'.
  9802. +-
  9803. +-   The order to add to the array is:
  9804. +-      temporary_env
  9805. +-      list of var contexts whose head is shell_variables
  9806. +-      shell_functions
  9807. +-
  9808. +-  This is the shell variable lookup order.  We add only new variable
  9809. +-  names at each step, which allows local variables and variables in
  9810. +-  the temporary environments to shadow variables in the global (or
  9811. +-  any previous) scope.
  9812. +-*/
  9813. +-
  9814. +-static int
  9815. +-n_shell_variables ()
  9816. +-{
  9817. +-  VAR_CONTEXT *vc;
  9818. +-  int n;
  9819. +-
  9820. +-  for (n = 0, vc = shell_variables; vc; vc = vc->down)
  9821. +-    n += HASH_ENTRIES (vc->table);
  9822. +-  return n;
  9823. +-}
  9824. +-
  9825. +-int
  9826. +-chkexport (name)
  9827. +-     char *name;
  9828. +-{
  9829. +-  SHELL_VAR *v;
  9830. +-
  9831. +-  v = find_variable (name);
  9832. +-  if (v && exported_p (v))
  9833. +-    {
  9834. +-      array_needs_making = 1;
  9835. +-      maybe_make_export_env ();
  9836. +-      return 1;
  9837. +-    }
  9838. +-  return 0;
  9839. +-}
  9840. +-
  9841. +-void
  9842. +-maybe_make_export_env ()
  9843. +-{
  9844. +-  register char **temp_array;
  9845. +-  int new_size;
  9846. +-  VAR_CONTEXT *tcxt;
  9847. +-
  9848. +-  if (array_needs_making)
  9849. +-    {
  9850. +-      if (export_env)
  9851. +-      strvec_flush (export_env);
  9852. +-
  9853. +-      /* Make a guess based on how many shell variables and functions we
  9854. +-       have.  Since there will always be array variables, and array
  9855. +-       variables are not (yet) exported, this will always be big enough
  9856. +-       for the exported variables and functions. */
  9857. +-      new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
  9858. +-               HASH_ENTRIES (temporary_env);
  9859. +-      if (new_size > export_env_size)
  9860. +-      {
  9861. +-        export_env_size = new_size;
  9862. +-        export_env = strvec_resize (export_env, export_env_size);
  9863. +-        environ = export_env;
  9864. +-      }
  9865. +-      export_env[export_env_index = 0] = (char *)NULL;
  9866. +-
  9867. +-      /* Make a dummy variable context from the temporary_env, stick it on
  9868. +-       the front of shell_variables, call make_var_export_array on the
  9869. +-       whole thing to flatten it, and convert the list of SHELL_VAR *s
  9870. +-       to the form needed by the environment. */
  9871. +-      if (temporary_env)
  9872. +-      {
  9873. +-        tcxt = new_var_context ((char *)NULL, 0);
  9874. +-        tcxt->table = temporary_env;
  9875. +-        tcxt->down = shell_variables;
  9876. +-      }
  9877. +-      else
  9878. +-      tcxt = shell_variables;
  9879. +-      
  9880. +-      temp_array = make_var_export_array (tcxt);
  9881. +-      if (temp_array)
  9882. +-      add_temp_array_to_env (temp_array, 0, 0);
  9883. +-
  9884. +-      if (tcxt != shell_variables)
  9885. +-      free (tcxt);
  9886. +-
  9887. +-#if defined (RESTRICTED_SHELL)
  9888. +-      /* Restricted shells may not export shell functions. */
  9889. +-      temp_array = restricted ? (char **)0 : make_func_export_array ();
  9890. +-#else
  9891. +-      temp_array = make_func_export_array ();
  9892. +-#endif
  9893. +-      if (temp_array)
  9894. +-      add_temp_array_to_env (temp_array, 0, 0);
  9895. +-
  9896. +-      array_needs_making = 0;
  9897. +-    }
  9898. +-}
  9899. +-
  9900. +-/* This is an efficiency hack.  PWD and OLDPWD are auto-exported, so
  9901. +-   we will need to remake the exported environment every time we
  9902. +-   change directories.  `_' is always put into the environment for
  9903. +-   every external command, so without special treatment it will always
  9904. +-   cause the environment to be remade.
  9905. +-
  9906. +-   If there is no other reason to make the exported environment, we can
  9907. +-   just update the variables in place and mark the exported environment
  9908. +-   as no longer needing a remake. */
  9909. +-void
  9910. +-update_export_env_inplace (env_prefix, preflen, value)
  9911. +-     char *env_prefix;
  9912. +-     int preflen;
  9913. +-     char *value;
  9914. +-{
  9915. +-  char *evar;
  9916. +-
  9917. +-  evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
  9918. +-  strcpy (evar, env_prefix);
  9919. +-  if (value)
  9920. +-    strcpy (evar + preflen, value);
  9921. +-  export_env = add_or_supercede_exported_var (evar, 0);
  9922. +-}
  9923. +-
  9924. +-/* We always put _ in the environment as the name of this command. */
  9925. +-void
  9926. +-put_command_name_into_env (command_name)
  9927. +-     char *command_name;
  9928. +-{
  9929. +-  update_export_env_inplace ("_=", 2, command_name);
  9930. +-}
  9931. +-
  9932. +-/* **************************************************************** */
  9933. +-/*                                                                */
  9934. +-/*                  Managing variable contexts                    */
  9935. +-/*                                                                */
  9936. +-/* **************************************************************** */
  9937. +-
  9938. +-/* Allocate and return a new variable context with NAME and FLAGS.
  9939. +-   NAME can be NULL. */
  9940. +-
  9941. +-VAR_CONTEXT *
  9942. +-new_var_context (name, flags)
  9943. +-     char *name;
  9944. +-     int flags;
  9945. +-{
  9946. +-  VAR_CONTEXT *vc;
  9947. +-
  9948. +-  vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
  9949. +-  vc->name = name ? savestring (name) : (char *)NULL;
  9950. +-  vc->scope = variable_context;
  9951. +-  vc->flags = flags;
  9952. +-
  9953. +-  vc->up = vc->down = (VAR_CONTEXT *)NULL;
  9954. +-  vc->table = (HASH_TABLE *)NULL;
  9955. +-
  9956. +-  return vc;
  9957. +-}
  9958. +-
  9959. +-/* Free a variable context and its data, including the hash table.  Dispose
  9960. +-   all of the variables. */
  9961. +-void
  9962. +-dispose_var_context (vc)
  9963. +-     VAR_CONTEXT *vc;
  9964. +-{
  9965. +-  FREE (vc->name);
  9966. +-
  9967. +-  if (vc->table)
  9968. +-    {
  9969. +-      delete_all_variables (vc->table);
  9970. +-      hash_dispose (vc->table);
  9971. +-    }
  9972. +-
  9973. +-  free (vc);
  9974. +-}
  9975. +-
  9976. +-/* Set VAR's scope level to the current variable context. */
  9977. +-static int
  9978. +-set_context (var)
  9979. +-     SHELL_VAR *var;
  9980. +-{
  9981. +-  return (var->context = variable_context);
  9982. +-}
  9983. +-
  9984. +-/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
  9985. +-   temporary variables, and push it onto shell_variables.  This is
  9986. +-   for shell functions. */
  9987. +-VAR_CONTEXT *
  9988. +-push_var_context (name, flags, tempvars)
  9989. +-     char *name;
  9990. +-     int flags;
  9991. +-     HASH_TABLE *tempvars;
  9992. +-{
  9993. +-  VAR_CONTEXT *vc;
  9994. +-
  9995. +-  vc = new_var_context (name, flags);
  9996. +-  vc->table = tempvars;
  9997. +-  if (tempvars)
  9998. +-    {
  9999. +-      /* Have to do this because the temp environment was created before
  10000. +-       variable_context was incremented. */
  10001. +-      flatten (tempvars, set_context, (VARLIST *)NULL, 0);
  10002. +-      vc->flags |= VC_HASTMPVAR;
  10003. +-    }
  10004. +-  vc->down = shell_variables;
  10005. +-  shell_variables->up = vc;
  10006. +-
  10007. +-  return (shell_variables = vc);
  10008. +-}
  10009. +-
  10010. +-static void
  10011. +-push_func_var (data)
  10012. +-     PTR_T data;
  10013. +-{
  10014. +-  SHELL_VAR *var, *v;
  10015. +-
  10016. +-  var = (SHELL_VAR *)data;
  10017. +-
  10018. +-  if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
  10019. +-    {
  10020. +-      /* Make sure we have a hash table to store the variable in while it is
  10021. +-       being propagated down to the global variables table.  Create one if
  10022. +-       we have to */
  10023. +-      if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
  10024. +-      shell_variables->table = hash_create (0);
  10025. +-      /* XXX - should we set v->context here? */
  10026. +-      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
  10027. +-      if (shell_variables == global_variables)
  10028. +-      var->attributes &= ~(att_tempvar|att_propagate);
  10029. +-      else
  10030. +-      shell_variables->flags |= VC_HASTMPVAR;
  10031. +-      v->attributes |= var->attributes;
  10032. +-    }
  10033. +-  else
  10034. +-    stupidly_hack_special_variables (var->name);      /* XXX */
  10035. +-
  10036. +-  dispose_variable (var);
  10037. +-}
  10038. +-
  10039. +-/* Pop the top context off of VCXT and dispose of it, returning the rest of
  10040. +-   the stack. */
  10041. +-void
  10042. +-pop_var_context ()
  10043. +-{
  10044. +-  VAR_CONTEXT *ret, *vcxt;
  10045. +-
  10046. +-  vcxt = shell_variables;
  10047. +-  if (vc_isfuncenv (vcxt) == 0)
  10048. +-    {
  10049. +-      internal_error (_("pop_var_context: head of shell_variables not a function context"));
  10050. +-      return;
  10051. +-    }
  10052. +-
  10053. +-  if (ret = vcxt->down)
  10054. +-    {
  10055. +-      ret->up = (VAR_CONTEXT *)NULL;
  10056. +-      shell_variables = ret;
  10057. +-      if (vcxt->table)
  10058. +-      hash_flush (vcxt->table, push_func_var);
  10059. +-      dispose_var_context (vcxt);
  10060. +-    }
  10061. +-  else
  10062. +-    internal_error (_("pop_var_context: no global_variables context"));
  10063. +-}
  10064. +-
  10065. +-/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
  10066. +-   all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
  10067. +-void
  10068. +-delete_all_contexts (vcxt)
  10069. +-     VAR_CONTEXT *vcxt;
  10070. +-{
  10071. +-  VAR_CONTEXT *v, *t;
  10072. +-
  10073. +-  for (v = vcxt; v != global_variables; v = t)
  10074. +-    {
  10075. +-      t = v->down;
  10076. +-      dispose_var_context (v);
  10077. +-    }    
  10078. +-
  10079. +-  delete_all_variables (global_variables->table);
  10080. +-  shell_variables = global_variables;
  10081. +-}
  10082. +-
  10083. +-/* **************************************************************** */
  10084. +-/*                                                                */
  10085. +-/*       Pushing and Popping temporary variable scopes            */
  10086. +-/*                                                                */
  10087. +-/* **************************************************************** */
  10088. +-
  10089. +-VAR_CONTEXT *
  10090. +-push_scope (flags, tmpvars)
  10091. +-     int flags;
  10092. +-     HASH_TABLE *tmpvars;
  10093. +-{
  10094. +-  return (push_var_context ((char *)NULL, flags, tmpvars));
  10095. +-}
  10096. +-
  10097. +-static void
  10098. +-push_exported_var (data)
  10099. +-     PTR_T data;
  10100. +-{
  10101. +-  SHELL_VAR *var, *v;
  10102. +-
  10103. +-  var = (SHELL_VAR *)data;
  10104. +-
  10105. +-  /* If a temp var had its export attribute set, or it's marked to be
  10106. +-     propagated, bind it in the previous scope before disposing it. */
  10107. +-  /* XXX - This isn't exactly right, because all tempenv variables have the
  10108. +-    export attribute set. */
  10109. +-#if 0
  10110. +-  if (exported_p (var) || (var->attributes & att_propagate))
  10111. +-#else
  10112. +-  if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
  10113. +-#endif
  10114. +-    {
  10115. +-      var->attributes &= ~att_tempvar;                /* XXX */
  10116. +-      v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
  10117. +-      if (shell_variables == global_variables)
  10118. +-      var->attributes &= ~att_propagate;
  10119. +-      v->attributes |= var->attributes;
  10120. +-    }
  10121. +-  else
  10122. +-    stupidly_hack_special_variables (var->name);      /* XXX */
  10123. +-
  10124. +-  dispose_variable (var);
  10125. +-}
  10126. +-
  10127. +-void
  10128. +-pop_scope (is_special)
  10129. +-     int is_special;
  10130. +-{
  10131. +-  VAR_CONTEXT *vcxt, *ret;
  10132. +-
  10133. +-  vcxt = shell_variables;
  10134. +-  if (vc_istempscope (vcxt) == 0)
  10135. +-    {
  10136. +-      internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
  10137. +-      return;
  10138. +-    }
  10139. +-
  10140. +-  ret = vcxt->down;
  10141. +-  if (ret)
  10142. +-    ret->up = (VAR_CONTEXT *)NULL;
  10143. +-
  10144. +-  shell_variables = ret;
  10145. +-
  10146. +-  /* Now we can take care of merging variables in VCXT into set of scopes
  10147. +-     whose head is RET (shell_variables). */
  10148. +-  FREE (vcxt->name);
  10149. +-  if (vcxt->table)
  10150. +-    {
  10151. +-      if (is_special)
  10152. +-      hash_flush (vcxt->table, push_func_var);
  10153. +-      else
  10154. +-      hash_flush (vcxt->table, push_exported_var);
  10155. +-      hash_dispose (vcxt->table);
  10156. +-    }
  10157. +-  free (vcxt);
  10158. +-
  10159. +-  sv_ifs ("IFS");     /* XXX here for now */
  10160. +-}
  10161. +-
  10162. +-/* **************************************************************** */
  10163. +-/*                                                                */
  10164. +-/*             Pushing and Popping function contexts              */
  10165. +-/*                                                                */
  10166. +-/* **************************************************************** */
  10167. +-
  10168. +-static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
  10169. +-static int dollar_arg_stack_slots;
  10170. +-static int dollar_arg_stack_index;
  10171. +-
  10172. +-/* XXX - we might want to consider pushing and popping the `getopts' state
  10173. +-   when we modify the positional parameters. */
  10174. +-void
  10175. +-push_context (name, is_subshell, tempvars)
  10176. +-     char *name;      /* function name */
  10177. +-     int is_subshell;
  10178. +-     HASH_TABLE *tempvars;
  10179. +-{
  10180. +-  if (is_subshell == 0)
  10181. +-    push_dollar_vars ();
  10182. +-  variable_context++;
  10183. +-  push_var_context (name, VC_FUNCENV, tempvars);
  10184. +-}
  10185. +-
  10186. +-/* Only called when subshell == 0, so we don't need to check, and can
  10187. +-   unconditionally pop the dollar vars off the stack. */
  10188. +-void
  10189. +-pop_context ()
  10190. +-{
  10191. +-  pop_dollar_vars ();
  10192. +-  variable_context--;
  10193. +-  pop_var_context ();
  10194. +-
  10195. +-  sv_ifs ("IFS");             /* XXX here for now */
  10196. +-}
  10197. +-
  10198. +-/* Save the existing positional parameters on a stack. */
  10199. +-void
  10200. +-push_dollar_vars ()
  10201. +-{
  10202. +-  if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
  10203. +-    {
  10204. +-      dollar_arg_stack = (WORD_LIST **)
  10205. +-      xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
  10206. +-                * sizeof (WORD_LIST *));
  10207. +-    }
  10208. +-  dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
  10209. +-  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  10210. +-}
  10211. +-
  10212. +-/* Restore the positional parameters from our stack. */
  10213. +-void
  10214. +-pop_dollar_vars ()
  10215. +-{
  10216. +-  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
  10217. +-    return;
  10218. +-
  10219. +-  remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
  10220. +-  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  10221. +-  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  10222. +-  set_dollar_vars_unchanged ();
  10223. +-}
  10224. +-
  10225. +-void
  10226. +-dispose_saved_dollar_vars ()
  10227. +-{
  10228. +-  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
  10229. +-    return;
  10230. +-
  10231. +-  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  10232. +-  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
  10233. +-}
  10234. +-
  10235. +-/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
  10236. +-
  10237. +-void
  10238. +-push_args (list)
  10239. +-     WORD_LIST *list;
  10240. +-{
  10241. +-#if defined (ARRAY_VARS) && defined (DEBUGGER)
  10242. +-  SHELL_VAR *bash_argv_v, *bash_argc_v;
  10243. +-  ARRAY *bash_argv_a, *bash_argc_a;
  10244. +-  WORD_LIST *l;
  10245. +-  arrayind_t i;
  10246. +-  char *t;
  10247. +-
  10248. +-  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
  10249. +-  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
  10250. +-
  10251. +-  for (l = list, i = 0; l; l = l->next, i++)
  10252. +-    array_push (bash_argv_a, l->word->word);
  10253. +-
  10254. +-  t = itos (i);
  10255. +-  array_push (bash_argc_a, t);
  10256. +-  free (t);
  10257. +-#endif /* ARRAY_VARS && DEBUGGER */
  10258. +-}
  10259. +-
  10260. +-/* Remove arguments from BASH_ARGV array.  Pop top element off BASH_ARGC
  10261. +-   array and use that value as the count of elements to remove from
  10262. +-   BASH_ARGV. */
  10263. +-void
  10264. +-pop_args ()
  10265. +-{
  10266. +-#if defined (ARRAY_VARS) && defined (DEBUGGER)
  10267. +-  SHELL_VAR *bash_argv_v, *bash_argc_v;
  10268. +-  ARRAY *bash_argv_a, *bash_argc_a;
  10269. +-  ARRAY_ELEMENT *ce;
  10270. +-  intmax_t i;
  10271. +-
  10272. +-  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
  10273. +-  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
  10274. +-
  10275. +-  ce = array_shift (bash_argc_a, 1, 0);
  10276. +-  if (ce == 0 || legal_number (element_value (ce), &i) == 0)
  10277. +-    i = 0;
  10278. +-
  10279. +-  for ( ; i > 0; i--)
  10280. +-    array_pop (bash_argv_a);
  10281. +-  array_dispose_element (ce);
  10282. +-#endif /* ARRAY_VARS && DEBUGGER */
  10283. +-}
  10284. +-
  10285. +-/*************************************************
  10286. +- *                                             *
  10287. +- *    Functions to manage special variables    *
  10288. +- *                                             *
  10289. +- *************************************************/
  10290. +-
  10291. +-/* Extern declarations for variables this code has to manage. */
  10292. +-extern int eof_encountered, eof_encountered_limit, ignoreeof;
  10293. +-
  10294. +-#if defined (READLINE)
  10295. +-extern int hostname_list_initialized;
  10296. +-#endif
  10297. +-
  10298. +-/* An alist of name.function for each special variable.  Most of the
  10299. +-   functions don't do much, and in fact, this would be faster with a
  10300. +-   switch statement, but by the end of this file, I am sick of switch
  10301. +-   statements. */
  10302. +-
  10303. +-#define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
  10304. +-
  10305. +-/* This table will be sorted with qsort() the first time it's accessed. */
  10306. +-struct name_and_function {
  10307. +-  char *name;
  10308. +-  sh_sv_func_t *function;
  10309. +-};
  10310. +-
  10311. +-static struct name_and_function special_vars[] = {
  10312. +-  { "BASH_COMPAT", sv_shcompat },
  10313. +-  { "BASH_XTRACEFD", sv_xtracefd },
  10314. +-
  10315. +-#if defined (JOB_CONTROL)
  10316. +-  { "CHILD_MAX", sv_childmax },
  10317. +-#endif
  10318. +-
  10319. +-#if defined (READLINE)
  10320. +-#  if defined (STRICT_POSIX)
  10321. +-  { "COLUMNS", sv_winsize },
  10322. +-#  endif
  10323. +-  { "COMP_WORDBREAKS", sv_comp_wordbreaks },
  10324. +-#endif
  10325. +-
  10326. +-  { "FUNCNEST", sv_funcnest },
  10327. +-
  10328. +-  { "GLOBIGNORE", sv_globignore },
  10329. +-
  10330. +-#if defined (HISTORY)
  10331. +-  { "HISTCONTROL", sv_history_control },
  10332. +-  { "HISTFILESIZE", sv_histsize },
  10333. +-  { "HISTIGNORE", sv_histignore },
  10334. +-  { "HISTSIZE", sv_histsize },
  10335. +-  { "HISTTIMEFORMAT", sv_histtimefmt },
  10336. +-#endif
  10337. +-
  10338. +-#if defined (__CYGWIN__)
  10339. +-  { "HOME", sv_home },
  10340. +-#endif
  10341. +-
  10342. +-#if defined (READLINE)
  10343. +-  { "HOSTFILE", sv_hostfile },
  10344. +-#endif
  10345. +-
  10346. +-  { "IFS", sv_ifs },
  10347. +-  { "IGNOREEOF", sv_ignoreeof },
  10348. +-
  10349. +-  { "LANG", sv_locale },
  10350. +-  { "LC_ALL", sv_locale },
  10351. +-  { "LC_COLLATE", sv_locale },
  10352. +-  { "LC_CTYPE", sv_locale },
  10353. +-  { "LC_MESSAGES", sv_locale },
  10354. +-  { "LC_NUMERIC", sv_locale },
  10355. +-  { "LC_TIME", sv_locale },
  10356. +-
  10357. +-#if defined (READLINE) && defined (STRICT_POSIX)
  10358. +-  { "LINES", sv_winsize },
  10359. +-#endif
  10360. +-
  10361. +-  { "MAIL", sv_mail },
  10362. +-  { "MAILCHECK", sv_mail },
  10363. +-  { "MAILPATH", sv_mail },
  10364. +-
  10365. +-  { "OPTERR", sv_opterr },
  10366. +-  { "OPTIND", sv_optind },
  10367. +-
  10368. +-  { "PATH", sv_path },
  10369. +-  { "POSIXLY_CORRECT", sv_strict_posix },
  10370. +-
  10371. +-#if defined (READLINE)
  10372. +-  { "TERM", sv_terminal },
  10373. +-  { "TERMCAP", sv_terminal },
  10374. +-  { "TERMINFO", sv_terminal },
  10375. +-#endif /* READLINE */
  10376. +-
  10377. +-  { "TEXTDOMAIN", sv_locale },
  10378. +-  { "TEXTDOMAINDIR", sv_locale },
  10379. +-
  10380. +-#if defined (HAVE_TZSET)
  10381. +-  { "TZ", sv_tz },
  10382. +-#endif
  10383. +-
  10384. +-#if defined (HISTORY) && defined (BANG_HISTORY)
  10385. +-  { "histchars", sv_histchars },
  10386. +-#endif /* HISTORY && BANG_HISTORY */
  10387. +-
  10388. +-  { "ignoreeof", sv_ignoreeof },
  10389. +-
  10390. +-  { (char *)0, (sh_sv_func_t *)0 }
  10391. +-};
  10392. +-
  10393. +-#define N_SPECIAL_VARS        (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
  10394. +-
  10395. +-static int
  10396. +-sv_compare (sv1, sv2)
  10397. +-     struct name_and_function *sv1, *sv2;
  10398. +-{
  10399. +-  int r;
  10400. +-
  10401. +-  if ((r = sv1->name[0] - sv2->name[0]) == 0)
  10402. +-    r = strcmp (sv1->name, sv2->name);
  10403. +-  return r;
  10404. +-}
  10405. +-
  10406. +-static inline int
  10407. +-find_special_var (name)
  10408. +-     const char *name;
  10409. +-{
  10410. +-  register int i, r;
  10411. +-
  10412. +-  for (i = 0; special_vars[i].name; i++)
  10413. +-    {
  10414. +-      r = special_vars[i].name[0] - name[0];
  10415. +-      if (r == 0)
  10416. +-      r = strcmp (special_vars[i].name, name);
  10417. +-      if (r == 0)
  10418. +-      return i;
  10419. +-      else if (r > 0)
  10420. +-      /* Can't match any of rest of elements in sorted list.  Take this out
  10421. +-         if it causes problems in certain environments. */
  10422. +-      break;
  10423. +-    }
  10424. +-  return -1;
  10425. +-}
  10426. +-
  10427. +-/* The variable in NAME has just had its state changed.  Check to see if it
  10428. +-   is one of the special ones where something special happens. */
  10429. +-void
  10430. +-stupidly_hack_special_variables (name)
  10431. +-     char *name;
  10432. +-{
  10433. +-  static int sv_sorted = 0;
  10434. +-  int i;
  10435. +-
  10436. +-  if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
  10437. +-    {
  10438. +-      qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
  10439. +-              (QSFUNC *)sv_compare);
  10440. +-      sv_sorted = 1;
  10441. +-    }
  10442. +-
  10443. +-  i = find_special_var (name);
  10444. +-  if (i != -1)
  10445. +-    (*(special_vars[i].function)) (name);
  10446. +-}
  10447. +-
  10448. +-/* Special variables that need hooks to be run when they are unset as part
  10449. +-   of shell reinitialization should have their sv_ functions run here. */
  10450. +-void
  10451. +-reinit_special_variables ()
  10452. +-{
  10453. +-#if defined (READLINE)
  10454. +-  sv_comp_wordbreaks ("COMP_WORDBREAKS");
  10455. +-#endif
  10456. +-  sv_globignore ("GLOBIGNORE");
  10457. +-  sv_opterr ("OPTERR");
  10458. +-}
  10459. +-
  10460. +-void
  10461. +-sv_ifs (name)
  10462. +-     char *name;
  10463. +-{
  10464. +-  SHELL_VAR *v;
  10465. +-
  10466. +-  v = find_variable ("IFS");
  10467. +-  setifs (v);
  10468. +-}
  10469. +-
  10470. +-/* What to do just after the PATH variable has changed. */
  10471. +-void
  10472. +-sv_path (name)
  10473. +-     char *name;
  10474. +-{
  10475. +-  /* hash -r */
  10476. +-  phash_flush ();
  10477. +-}
  10478. +-
  10479. +-/* What to do just after one of the MAILxxxx variables has changed.  NAME
  10480. +-   is the name of the variable.  This is called with NAME set to one of
  10481. +-   MAIL, MAILCHECK, or MAILPATH.  */
  10482. +-void
  10483. +-sv_mail (name)
  10484. +-     char *name;
  10485. +-{
  10486. +-  /* If the time interval for checking the files has changed, then
  10487. +-     reset the mail timer.  Otherwise, one of the pathname vars
  10488. +-     to the users mailbox has changed, so rebuild the array of
  10489. +-     filenames. */
  10490. +-  if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
  10491. +-    reset_mail_timer ();
  10492. +-  else
  10493. +-    {
  10494. +-      free_mail_files ();
  10495. +-      remember_mail_dates ();
  10496. +-    }
  10497. +-}
  10498. +-
  10499. +-void
  10500. +-sv_funcnest (name)
  10501. +-     char *name;
  10502. +-{
  10503. +-  SHELL_VAR *v;
  10504. +-  intmax_t num;
  10505. +-
  10506. +-  v = find_variable (name);
  10507. +-  if (v == 0)
  10508. +-    funcnest_max = 0;
  10509. +-  else if (legal_number (value_cell (v), &num) == 0)
  10510. +-    funcnest_max = 0;
  10511. +-  else
  10512. +-    funcnest_max = num;
  10513. +-}
  10514. +-
  10515. +-/* What to do when GLOBIGNORE changes. */
  10516. +-void
  10517. +-sv_globignore (name)
  10518. +-     char *name;
  10519. +-{
  10520. +-  if (privileged_mode == 0)
  10521. +-    setup_glob_ignore (name);
  10522. +-}
  10523. +-
  10524. +-#if defined (READLINE)
  10525. +-void
  10526. +-sv_comp_wordbreaks (name)
  10527. +-     char *name;
  10528. +-{
  10529. +-  SHELL_VAR *sv;
  10530. +-
  10531. +-  sv = find_variable (name);
  10532. +-  if (sv == 0)
  10533. +-    reset_completer_word_break_chars ();
  10534. +-}
  10535. +-
  10536. +-/* What to do just after one of the TERMxxx variables has changed.
  10537. +-   If we are an interactive shell, then try to reset the terminal
  10538. +-   information in readline. */
  10539. +-void
  10540. +-sv_terminal (name)
  10541. +-     char *name;
  10542. +-{
  10543. +-  if (interactive_shell && no_line_editing == 0)
  10544. +-    rl_reset_terminal (get_string_value ("TERM"));
  10545. +-}
  10546. +-
  10547. +-void
  10548. +-sv_hostfile (name)
  10549. +-     char *name;
  10550. +-{
  10551. +-  SHELL_VAR *v;
  10552. +-
  10553. +-  v = find_variable (name);
  10554. +-  if (v == 0)
  10555. +-    clear_hostname_list ();
  10556. +-  else
  10557. +-    hostname_list_initialized = 0;
  10558. +-}
  10559. +-
  10560. +-#if defined (STRICT_POSIX)
  10561. +-/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
  10562. +-   found in the initial environment) to override the terminal size reported by
  10563. +-   the kernel. */
  10564. +-void
  10565. +-sv_winsize (name)
  10566. +-     char *name;
  10567. +-{
  10568. +-  SHELL_VAR *v;
  10569. +-  intmax_t xd;
  10570. +-  int d;
  10571. +-
  10572. +-  if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
  10573. +-    return;
  10574. +-
  10575. +-  v = find_variable (name);
  10576. +-  if (v == 0 || var_isnull (v))
  10577. +-    rl_reset_screen_size ();
  10578. +-  else
  10579. +-    {
  10580. +-      if (legal_number (value_cell (v), &xd) == 0)
  10581. +-      return;
  10582. +-      winsize_assignment = 1;
  10583. +-      d = xd;                 /* truncate */
  10584. +-      if (name[0] == 'L')     /* LINES */
  10585. +-      rl_set_screen_size (d, -1);
  10586. +-      else                    /* COLUMNS */
  10587. +-      rl_set_screen_size (-1, d);
  10588. +-      winsize_assignment = 0;
  10589. +-    }
  10590. +-}
  10591. +-#endif /* STRICT_POSIX */
  10592. +-#endif /* READLINE */
  10593. +-
  10594. +-/* Update the value of HOME in the export environment so tilde expansion will
  10595. +-   work on cygwin. */
  10596. +-#if defined (__CYGWIN__)
  10597. +-sv_home (name)
  10598. +-     char *name;
  10599. +-{
  10600. +-  array_needs_making = 1;
  10601. +-  maybe_make_export_env ();
  10602. +-}
  10603. +-#endif
  10604. +-
  10605. +-#if defined (HISTORY)
  10606. +-/* What to do after the HISTSIZE or HISTFILESIZE variables change.
  10607. +-   If there is a value for this HISTSIZE (and it is numeric), then stifle
  10608. +-   the history.  Otherwise, if there is NO value for this variable,
  10609. +-   unstifle the history.  If name is HISTFILESIZE, and its value is
  10610. +-   numeric, truncate the history file to hold no more than that many
  10611. +-   lines. */
  10612. +-void
  10613. +-sv_histsize (name)
  10614. +-     char *name;
  10615. +-{
  10616. +-  char *temp;
  10617. +-  intmax_t num;
  10618. +-  int hmax;
  10619. +-
  10620. +-  temp = get_string_value (name);
  10621. +-
  10622. +-  if (temp && *temp)
  10623. +-    {
  10624. +-      if (legal_number (temp, &num))
  10625. +-      {
  10626. +-        hmax = num;
  10627. +-        if (hmax < 0 && name[4] == 'S')
  10628. +-          unstifle_history ();        /* unstifle history if HISTSIZE < 0 */
  10629. +-        else if (name[4] == 'S')
  10630. +-          {
  10631. +-            stifle_history (hmax);
  10632. +-            hmax = where_history ();
  10633. +-            if (history_lines_this_session > hmax)
  10634. +-              history_lines_this_session = hmax;
  10635. +-          }
  10636. +-        else if (hmax >= 0)   /* truncate HISTFILE if HISTFILESIZE >= 0 */
  10637. +-          {
  10638. +-            history_truncate_file (get_string_value ("HISTFILE"), hmax);
  10639. +-            if (hmax <= history_lines_in_file)
  10640. +-              history_lines_in_file = hmax;
  10641. +-          }
  10642. +-      }
  10643. +-    }
  10644. +-  else if (name[4] == 'S')
  10645. +-    unstifle_history ();
  10646. +-}
  10647. +-
  10648. +-/* What to do after the HISTIGNORE variable changes. */
  10649. +-void
  10650. +-sv_histignore (name)
  10651. +-     char *name;
  10652. +-{
  10653. +-  setup_history_ignore (name);
  10654. +-}
  10655. +-
  10656. +-/* What to do after the HISTCONTROL variable changes. */
  10657. +-void
  10658. +-sv_history_control (name)
  10659. +-     char *name;
  10660. +-{
  10661. +-  char *temp;
  10662. +-  char *val;
  10663. +-  int tptr;
  10664. +-
  10665. +-  history_control = 0;
  10666. +-  temp = get_string_value (name);
  10667. +-
  10668. +-  if (temp == 0 || *temp == 0)
  10669. +-    return;
  10670. +-
  10671. +-  tptr = 0;
  10672. +-  while (val = extract_colon_unit (temp, &tptr))
  10673. +-    {
  10674. +-      if (STREQ (val, "ignorespace"))
  10675. +-      history_control |= HC_IGNSPACE;
  10676. +-      else if (STREQ (val, "ignoredups"))
  10677. +-      history_control |= HC_IGNDUPS;
  10678. +-      else if (STREQ (val, "ignoreboth"))
  10679. +-      history_control |= HC_IGNBOTH;
  10680. +-      else if (STREQ (val, "erasedups"))
  10681. +-      history_control |= HC_ERASEDUPS;
  10682. +-
  10683. +-      free (val);
  10684. +-    }
  10685. +-}
  10686. +-
  10687. +-#if defined (BANG_HISTORY)
  10688. +-/* Setting/unsetting of the history expansion character. */
  10689. +-void
  10690. +-sv_histchars (name)
  10691. +-     char *name;
  10692. +-{
  10693. +-  char *temp;
  10694. +-
  10695. +-  temp = get_string_value (name);
  10696. +-  if (temp)
  10697. +-    {
  10698. +-      history_expansion_char = *temp;
  10699. +-      if (temp[0] && temp[1])
  10700. +-      {
  10701. +-        history_subst_char = temp[1];
  10702. +-        if (temp[2])
  10703. +-            history_comment_char = temp[2];
  10704. +-      }
  10705. +-    }
  10706. +-  else
  10707. +-    {
  10708. +-      history_expansion_char = '!';
  10709. +-      history_subst_char = '^';
  10710. +-      history_comment_char = '#';
  10711. +-    }
  10712. +-}
  10713. +-#endif /* BANG_HISTORY */
  10714. +-
  10715. +-void
  10716. +-sv_histtimefmt (name)
  10717. +-     char *name;
  10718. +-{
  10719. +-  SHELL_VAR *v;
  10720. +-
  10721. +-  if (v = find_variable (name))
  10722. +-    {
  10723. +-      if (history_comment_char == 0)
  10724. +-      history_comment_char = '#';
  10725. +-    }
  10726. +-  history_write_timestamps = (v != 0);
  10727. +-}
  10728. +-#endif /* HISTORY */
  10729. +-
  10730. +-#if defined (HAVE_TZSET)
  10731. +-void
  10732. +-sv_tz (name)
  10733. +-     char *name;
  10734. +-{
  10735. +-  if (chkexport (name))
  10736. +-    tzset ();
  10737. +-}
  10738. +-#endif
  10739. +-
  10740. +-/* If the variable exists, then the value of it can be the number
  10741. +-   of times we actually ignore the EOF.  The default is small,
  10742. +-   (smaller than csh, anyway). */
  10743. +-void
  10744. +-sv_ignoreeof (name)
  10745. +-     char *name;
  10746. +-{
  10747. +-  SHELL_VAR *tmp_var;
  10748. +-  char *temp;
  10749. +-
  10750. +-  eof_encountered = 0;
  10751. +-
  10752. +-  tmp_var = find_variable (name);
  10753. +-  ignoreeof = tmp_var != 0;
  10754. +-  temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
  10755. +-  if (temp)
  10756. +-    eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
  10757. +-  set_shellopts ();   /* make sure `ignoreeof' is/is not in $SHELLOPTS */
  10758. +-}
  10759. +-
  10760. +-void
  10761. +-sv_optind (name)
  10762. +-     char *name;
  10763. +-{
  10764. +-  char *tt;
  10765. +-  int s;
  10766. +-
  10767. +-  tt = get_string_value ("OPTIND");
  10768. +-  if (tt && *tt)
  10769. +-    {
  10770. +-      s = atoi (tt);
  10771. +-
  10772. +-      /* According to POSIX, setting OPTIND=1 resets the internal state
  10773. +-       of getopt (). */
  10774. +-      if (s < 0 || s == 1)
  10775. +-      s = 0;
  10776. +-    }
  10777. +-  else
  10778. +-    s = 0;
  10779. +-  getopts_reset (s);
  10780. +-}
  10781. +-
  10782. +-void
  10783. +-sv_opterr (name)
  10784. +-     char *name;
  10785. +-{
  10786. +-  char *tt;
  10787. +-
  10788. +-  tt = get_string_value ("OPTERR");
  10789. +-  sh_opterr = (tt && *tt) ? atoi (tt) : 1;
  10790. +-}
  10791. +-
  10792. +-void
  10793. +-sv_strict_posix (name)
  10794. +-     char *name;
  10795. +-{
  10796. +-  SET_INT_VAR (name, posixly_correct);
  10797. +-  posix_initialize (posixly_correct);
  10798. +-#if defined (READLINE)
  10799. +-  if (interactive_shell)
  10800. +-    posix_readline_initialize (posixly_correct);
  10801. +-#endif /* READLINE */
  10802. +-  set_shellopts ();   /* make sure `posix' is/is not in $SHELLOPTS */
  10803. +-}
  10804. +-
  10805. +-void
  10806. +-sv_locale (name)
  10807. +-     char *name;
  10808. +-{
  10809. +-  char *v;
  10810. +-  int r;
  10811. +-
  10812. +-  v = get_string_value (name);
  10813. +-  if (name[0] == 'L' && name[1] == 'A')       /* LANG */
  10814. +-    r = set_lang (name, v);
  10815. +-  else
  10816. +-    r = set_locale_var (name, v);             /* LC_*, TEXTDOMAIN* */
  10817. +-
  10818. +-#if 1
  10819. +-  if (r == 0 && posixly_correct)
  10820. +-    last_command_exit_value = 1;
  10821. +-#endif
  10822. +-}
  10823. +-
  10824. +-#if defined (ARRAY_VARS)
  10825. +-void
  10826. +-set_pipestatus_array (ps, nproc)
  10827. +-     int *ps;
  10828. +-     int nproc;
  10829. +-{
  10830. +-  SHELL_VAR *v;
  10831. +-  ARRAY *a;
  10832. +-  ARRAY_ELEMENT *ae;
  10833. +-  register int i;
  10834. +-  char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
  10835. +-
  10836. +-  v = find_variable ("PIPESTATUS");
  10837. +-  if (v == 0)
  10838. +-    v = make_new_array_variable ("PIPESTATUS");
  10839. +-  if (array_p (v) == 0)
  10840. +-    return;           /* Do nothing if not an array variable. */
  10841. +-  a = array_cell (v);
  10842. +-
  10843. +-  if (a == 0 || array_num_elements (a) == 0)
  10844. +-    {
  10845. +-      for (i = 0; i < nproc; i++)     /* was ps[i] != -1, not i < nproc */
  10846. +-      {
  10847. +-        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  10848. +-        array_insert (a, i, t);
  10849. +-      }
  10850. +-      return;
  10851. +-    }
  10852. +-
  10853. +-  /* Fast case */
  10854. +-  if (array_num_elements (a) == nproc && nproc == 1)
  10855. +-    {
  10856. +-      ae = element_forw (a->head);
  10857. +-      free (element_value (ae));
  10858. +-      ae->value = itos (ps[0]);
  10859. +-    }
  10860. +-  else if (array_num_elements (a) <= nproc)
  10861. +-    {
  10862. +-      /* modify in array_num_elements members in place, then add */
  10863. +-      ae = a->head;
  10864. +-      for (i = 0; i < array_num_elements (a); i++)
  10865. +-      {
  10866. +-        ae = element_forw (ae);
  10867. +-        free (element_value (ae));
  10868. +-        ae->value = itos (ps[i]);
  10869. +-      }
  10870. +-      /* add any more */
  10871. +-      for ( ; i < nproc; i++)
  10872. +-      {
  10873. +-        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  10874. +-        array_insert (a, i, t);
  10875. +-      }
  10876. +-    }
  10877. +-  else
  10878. +-    {
  10879. +-      /* deleting elements.  it's faster to rebuild the array. */      
  10880. +-      array_flush (a);
  10881. +-      for (i = 0; ps[i] != -1; i++)
  10882. +-      {
  10883. +-        t = inttostr (ps[i], tbuf, sizeof (tbuf));
  10884. +-        array_insert (a, i, t);
  10885. +-      }
  10886. +-    }
  10887. +-}
  10888. +-
  10889. +-ARRAY *
  10890. +-save_pipestatus_array ()
  10891. +-{
  10892. +-  SHELL_VAR *v;
  10893. +-  ARRAY *a, *a2;
  10894. +-
  10895. +-  v = find_variable ("PIPESTATUS");
  10896. +-  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
  10897. +-    return ((ARRAY *)NULL);
  10898. +-    
  10899. +-  a = array_cell (v);
  10900. +-  a2 = array_copy (array_cell (v));
  10901. +-
  10902. +-  return a2;
  10903. +-}
  10904. +-
  10905. +-void
  10906. +-restore_pipestatus_array (a)
  10907. +-     ARRAY *a;
  10908. +-{
  10909. +-  SHELL_VAR *v;
  10910. +-  ARRAY *a2;
  10911. +-
  10912. +-  v = find_variable ("PIPESTATUS");
  10913. +-  /* XXX - should we still assign even if existing value is NULL? */
  10914. +-  if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
  10915. +-    return;
  10916. +-
  10917. +-  a2 = array_cell (v);
  10918. +-  var_setarray (v, a);
  10919. +-
  10920. +-  array_dispose (a2);
  10921. +-}
  10922. +-#endif
  10923. +-
  10924. +-void
  10925. +-set_pipestatus_from_exit (s)
  10926. +-     int s;
  10927. +-{
  10928. +-#if defined (ARRAY_VARS)
  10929. +-  static int v[2] = { 0, -1 };
  10930. +-
  10931. +-  v[0] = s;
  10932. +-  set_pipestatus_array (v, 1);
  10933. +-#endif
  10934. +-}
  10935. +-
  10936. +-void
  10937. +-sv_xtracefd (name)
  10938. +-     char *name;
  10939. +-{
  10940. +-  SHELL_VAR *v;
  10941. +-  char *t, *e;
  10942. +-  int fd;
  10943. +-  FILE *fp;
  10944. +-
  10945. +-  v = find_variable (name);
  10946. +-  if (v == 0)
  10947. +-    {
  10948. +-      xtrace_reset ();
  10949. +-      return;
  10950. +-    }
  10951. +-
  10952. +-  t = value_cell (v);
  10953. +-  if (t == 0 || *t == 0)
  10954. +-    xtrace_reset ();
  10955. +-  else
  10956. +-    {
  10957. +-      fd = (int)strtol (t, &e, 10);
  10958. +-      if (e != t && *e == '\0' && sh_validfd (fd))
  10959. +-      {
  10960. +-        fp = fdopen (fd, "w");
  10961. +-        if (fp == 0)
  10962. +-          internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
  10963. +-        else
  10964. +-          xtrace_set (fd, fp);
  10965. +-      }
  10966. +-      else
  10967. +-      internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
  10968. +-    }
  10969. +-}
  10970. +-
  10971. +-#define MIN_COMPAT_LEVEL 31
  10972. +-
  10973. +-void
  10974. +-sv_shcompat (name)
  10975. +-     char *name;
  10976. +-{
  10977. +-  SHELL_VAR *v;
  10978. +-  char *val;
  10979. +-  int tens, ones, compatval;
  10980. +-
  10981. +-  v = find_variable (name);
  10982. +-  if (v == 0)
  10983. +-    {
  10984. +-      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  10985. +-      set_compatibility_opts ();
  10986. +-      return;
  10987. +-    }
  10988. +-  val = value_cell (v);
  10989. +-  if (val == 0 || *val == '\0')
  10990. +-    {
  10991. +-      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  10992. +-      set_compatibility_opts ();
  10993. +-      return;
  10994. +-    }
  10995. +-  /* Handle decimal-like compatibility version specifications: 4.2 */
  10996. +-  if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
  10997. +-    {
  10998. +-      tens = val[0] - '0';
  10999. +-      ones = val[2] - '0';
  11000. +-      compatval = tens*10 + ones;
  11001. +-    }
  11002. +-  /* Handle integer-like compatibility version specifications: 42 */
  11003. +-  else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
  11004. +-    {
  11005. +-      tens = val[0] - '0';
  11006. +-      ones = val[1] - '0';
  11007. +-      compatval = tens*10 + ones;
  11008. +-    }
  11009. +-  else
  11010. +-    {
  11011. +-compat_error:
  11012. +-      internal_error (_("%s: %s: compatibility value out of range"), name, val);
  11013. +-      shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
  11014. +-      set_compatibility_opts ();
  11015. +-      return;
  11016. +-    }
  11017. +-
  11018. +-  if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
  11019. +-    goto compat_error;
  11020. +-
  11021. +-  shell_compatibility_level = compatval;
  11022. +-  set_compatibility_opts ();
  11023. +-}
  11024. +-
  11025. +-#if defined (JOB_CONTROL)
  11026. +-void
  11027. +-sv_childmax (name)
  11028. +-     char *name;
  11029. +-{
  11030. +-  char *tt;
  11031. +-  int s;
  11032. +-
  11033. +-  tt = get_string_value (name);
  11034. +-  s = (tt && *tt) ? atoi (tt) : 0;
  11035. +-  set_maxchild (s);
  11036. +-}
  11037. +-#endif
  11038. diff --git a/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch b/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
  11039. new file mode 100644
  11040. index 0000000..cda1797
  11041. --- /dev/null
  11042. +++ b/ptxdist/patches/bash-4.3.30/0003-Bash-4.3-patch-33.patch
  11043. @@ -0,0 +1,204 @@
  11044. +From: Chet Ramey <chet.ramey@case.edu>
  11045. +Date: Thu, 15 Jan 2015 10:21:08 -0500
  11046. +Subject: [PATCH] Bash-4.3 patch 33
  11047. +
  11048. +---
  11049. + bashline.c        |  6 ++++--
  11050. + builtins/common.h |  4 ++++
  11051. + builtins/read.def | 31 ++++++++++++++++++++++++++++---
  11052. + patchlevel.h      |  2 +-
  11053. + shell.c           |  9 +++++++++
  11054. + sig.c             |  6 ++++--
  11055. + 6 files changed, 50 insertions(+), 8 deletions(-)
  11056. +
  11057. +diff --git a/bashline.c b/bashline.c
  11058. +index 77ca033f2cc8..c87415171a4a 100644
  11059. +--- a/bashline.c
  11060. ++++ b/bashline.c
  11061. +@@ -202,6 +202,7 @@ extern int current_command_line_count, saved_command_line_count;
  11062. + extern int last_command_exit_value;
  11063. + extern int array_needs_making;
  11064. + extern int posixly_correct, no_symbolic_links;
  11065. ++extern int sigalrm_seen;
  11066. + extern char *current_prompt_string, *ps1_prompt;
  11067. + extern STRING_INT_ALIST word_token_alist[];
  11068. + extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
  11069. +@@ -4208,8 +4209,9 @@ bash_event_hook ()
  11070. + {
  11071. +   /* If we're going to longjmp to top_level, make sure we clean up readline.
  11072. +      check_signals will call QUIT, which will eventually longjmp to top_level,
  11073. +-     calling run_interrupt_trap along the way. */
  11074. +-  if (interrupt_state)
  11075. ++     calling run_interrupt_trap along the way.  The check for sigalrm_seen is
  11076. ++     to clean up the read builtin's state. */
  11077. ++  if (terminating_signal || interrupt_state || sigalrm_seen)
  11078. +     rl_cleanup_after_signal ();
  11079. +   bashline_reset_event_hook ();
  11080. +   check_signals_and_traps (); /* XXX */
  11081. +diff --git a/builtins/common.h b/builtins/common.h
  11082. +index cae16b10fb65..a1298cb9c84a 100644
  11083. +--- a/builtins/common.h
  11084. ++++ b/builtins/common.h
  11085. +@@ -122,6 +122,10 @@ extern void bash_logout __P((void));
  11086. + /* Functions from getopts.def */
  11087. + extern void getopts_reset __P((int));
  11088. +
  11089. ++/* Functions from read.def */
  11090. ++extern void read_tty_cleanup __P((void));
  11091. ++extern int read_tty_modified __P((void));
  11092. ++
  11093. + /* Functions from set.def */
  11094. + extern int minus_o_option_value __P((char *));
  11095. + extern void list_minus_o_opts __P((int, int));
  11096. +diff --git a/builtins/read.def b/builtins/read.def
  11097. +index 43971544d081..56c23010bbe8 100644
  11098. +--- a/builtins/read.def
  11099. ++++ b/builtins/read.def
  11100. +@@ -140,10 +140,12 @@ static void reset_alarm __P((void));
  11101. + procenv_t alrmbuf;
  11102. + int sigalrm_seen;
  11103. +
  11104. +-static int reading;
  11105. ++static int reading, tty_modified;
  11106. + static SigHandler *old_alrm;
  11107. + static unsigned char delim;
  11108. +
  11109. ++static struct ttsave termsave;
  11110. ++
  11111. + /* In all cases, SIGALRM just sets a flag that we check periodically.  This
  11112. +    avoids problems with the semi-tricky stuff we do with the xfree of
  11113. +    input_string at the top of the unwind-protect list (see below). */
  11114. +@@ -188,7 +190,6 @@ read_builtin (list)
  11115. +   struct stat tsb;
  11116. +   SHELL_VAR *var;
  11117. +   TTYSTRUCT ttattrs, ttset;
  11118. +-  struct ttsave termsave;
  11119. + #if defined (ARRAY_VARS)
  11120. +   WORD_LIST *alist;
  11121. + #endif
  11122. +@@ -221,7 +222,7 @@ read_builtin (list)
  11123. +   USE_VAR(ps2);
  11124. +   USE_VAR(lastsig);
  11125. +
  11126. +-  sigalrm_seen = reading = 0;
  11127. ++  sigalrm_seen = reading = tty_modified = 0;
  11128. +
  11129. +   i = 0;              /* Index into the string that we are reading. */
  11130. +   raw = edit = 0;     /* Not reading raw input by default. */
  11131. +@@ -438,6 +439,8 @@ read_builtin (list)
  11132. +         retval = 128+SIGALRM;
  11133. +         goto assign_vars;
  11134. +       }
  11135. ++      if (interactive_shell == 0)
  11136. ++      initialize_terminating_signals ();
  11137. +       old_alrm = set_signal_handler (SIGALRM, sigalrm);
  11138. +       add_unwind_protect (reset_alarm, (char *)NULL);
  11139. + #if defined (READLINE)
  11140. +@@ -482,7 +485,10 @@ read_builtin (list)
  11141. +         i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
  11142. +         if (i < 0)
  11143. +           sh_ttyerror (1);
  11144. ++        tty_modified = 1;
  11145. +         add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
  11146. ++        if (interactive_shell == 0)
  11147. ++          initialize_terminating_signals ();
  11148. +       }
  11149. +     }
  11150. +   else if (silent)    /* turn off echo but leave term in canonical mode */
  11151. +@@ -497,7 +503,10 @@ read_builtin (list)
  11152. +       if (i < 0)
  11153. +       sh_ttyerror (1);
  11154. +
  11155. ++      tty_modified = 1;
  11156. +       add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
  11157. ++      if (interactive_shell == 0)
  11158. ++      initialize_terminating_signals ();
  11159. +     }
  11160. +
  11161. +   /* This *must* be the top unwind-protect on the stack, so the manipulation
  11162. +@@ -588,6 +597,8 @@ read_builtin (list)
  11163. +           }
  11164. +         else
  11165. +           lastsig = 0;
  11166. ++        if (terminating_signal && tty_modified)
  11167. ++          ttyrestore (&termsave);     /* fix terminal before exiting */
  11168. +         CHECK_TERMSIG;
  11169. +         eof = 1;
  11170. +         break;
  11171. +@@ -978,6 +989,20 @@ ttyrestore (ttp)
  11172. +      struct ttsave *ttp;
  11173. + {
  11174. +   ttsetattr (ttp->fd, ttp->attrs);
  11175. ++  tty_modified = 0;
  11176. ++}
  11177. ++
  11178. ++void
  11179. ++read_tty_cleanup ()
  11180. ++{
  11181. ++  if (tty_modified)
  11182. ++    ttyrestore (&termsave);
  11183. ++}
  11184. ++
  11185. ++int
  11186. ++read_tty_modified ()
  11187. ++{
  11188. ++  return (tty_modified);
  11189. + }
  11190. +
  11191. + #if defined (READLINE)
  11192. +diff --git a/patchlevel.h b/patchlevel.h
  11193. +index b8bf38704ed2..cefe6bdd3a13 100644
  11194. +--- a/patchlevel.h
  11195. ++++ b/patchlevel.h
  11196. +@@ -25,6 +25,6 @@
  11197. +    regexp `^#define[  ]*PATCHLEVEL', since that's what support/mkversion.sh
  11198. +    looks for to find the patch level (for the sccs version string). */
  11199. +
  11200. +-#define PATCHLEVEL 32
  11201. ++#define PATCHLEVEL 33
  11202. +
  11203. + #endif /* _PATCHLEVEL_H_ */
  11204. +diff --git a/shell.c b/shell.c
  11205. +index bbc8a66cc2eb..2fd8179ba10d 100644
  11206. +--- a/shell.c
  11207. ++++ b/shell.c
  11208. +@@ -73,6 +73,7 @@
  11209. + #endif
  11210. +
  11211. + #if defined (READLINE)
  11212. ++#  include <readline/readline.h>
  11213. + #  include "bashline.h"
  11214. + #endif
  11215. +
  11216. +@@ -909,6 +910,14 @@ exit_shell (s)
  11217. +   fflush (stdout);            /* XXX */
  11218. +   fflush (stderr);
  11219. +
  11220. ++  /* Clean up the terminal if we are in a state where it's been modified. */
  11221. ++#if defined (READLINE)
  11222. ++  if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
  11223. ++    (*rl_deprep_term_function) ();
  11224. ++#endif
  11225. ++  if (read_tty_modified ())
  11226. ++    read_tty_cleanup ();
  11227. ++
  11228. +   /* Do trap[0] if defined.  Allow it to override the exit status
  11229. +      passed to us. */
  11230. +   if (signal_is_trapped (0))
  11231. +diff --git a/sig.c b/sig.c
  11232. +index 3b62ea5d7c5d..8bc45c17f478 100644
  11233. +--- a/sig.c
  11234. ++++ b/sig.c
  11235. +@@ -532,8 +532,10 @@ termsig_sighandler (sig)
  11236. + #if defined (READLINE)
  11237. +   /* Set the event hook so readline will call it after the signal handlers
  11238. +      finish executing, so if this interrupted character input we can get
  11239. +-     quick response. */
  11240. +-  if (interactive_shell && interactive && no_line_editing == 0)
  11241. ++     quick response.  If readline is active or has modified the terminal we
  11242. ++     need to set this no matter what the signal is, though the check for
  11243. ++     RL_STATE_TERMPREPPED is possibly redundant. */
  11244. ++  if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
  11245. +     bashline_set_event_hook ();
  11246. + #endif
  11247. +
  11248. diff --git a/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch b/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch
  11249. new file mode 100644
  11250. index 0000000..5154683
  11251. --- /dev/null
  11252. +++ b/ptxdist/patches/bash-4.3.30/0101-etc_bashrc_bashlogout.patch
  11253. @@ -0,0 +1,22 @@
  11254. +diff --git a/config-top.h b/config-top.h
  11255. +index 7a90b16..52d582a 100644
  11256. +--- a/config-top.h
  11257. ++++ b/config-top.h
  11258. +@@ -73,14 +73,14 @@
  11259. + #define KSH_COMPATIBLE_SELECT
  11260. +
  11261. + /* System-wide .bashrc file for interactive shells. */
  11262. +-/* #define SYS_BASHRC "/etc/bash.bashrc" */
  11263. ++#define SYS_BASHRC "/etc/bash.bashrc"
  11264. +
  11265. + /* System-wide .bash_logout for login shells. */
  11266. +-/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */
  11267. ++#define SYS_BASH_LOGOUT "/etc/bash.bash_logout"
  11268. +
  11269. + /* Define this to make non-interactive shells begun with argv[0][0] == '-'
  11270. +    run the startup files when not in posix mode. */
  11271. +-/* #define NON_INTERACTIVE_LOGIN_SHELLS */
  11272. ++#define NON_INTERACTIVE_LOGIN_SHELLS 1
  11273. +
  11274. + /* Define this if you want bash to try to check whether it's being run by
  11275. +    sshd and source the .bashrc if so (like the rshd behavior). */
  11276. diff --git a/ptxdist/patches/bash-4.3.30/series b/ptxdist/patches/bash-4.3.30/series
  11277. new file mode 100644
  11278. index 0000000..ed42ce1
  11279. --- /dev/null
  11280. +++ b/ptxdist/patches/bash-4.3.30/series
  11281. @@ -0,0 +1,4 @@
  11282. +0001-Bash-4.3-patch-31.patch
  11283. +0002-Bash-4.3-patch-32.patch
  11284. +0003-Bash-4.3-patch-33.patch
  11285. +0101-etc_bashrc_bashlogout.patch
  11286. diff --git a/ptxdist/projectroot/etc/passwd b/ptxdist/projectroot/etc/passwd
  11287. index 5df5a35..1d394b8 100644
  11288. --- a/ptxdist/projectroot/etc/passwd
  11289. +++ b/ptxdist/projectroot/etc/passwd
  11290. @@ -1,4 +1,4 @@
  11291. -root:x:0:0:root:/home:/bin/sh
  11292. +root:x:0:0:root:/home:/bin/bash
  11293.  daemon:x:1:1:daemon:/usr/sbin:/bin/sh
  11294.  ftp:x:11:101:ftp user:/home:/bin/false
  11295.  www:x:12:102:www user:/home:/bin/false
  11296. diff --git a/ptxdist/projectroot/etc/profile.environment b/ptxdist/projectroot/etc/profile.environment
  11297. index e4b85cc..cb47464 100644
  11298. --- a/ptxdist/projectroot/etc/profile.environment
  11299. +++ b/ptxdist/projectroot/etc/profile.environment
  11300. @@ -1,13 +1,11 @@
  11301. -# /etc/profile.environment - config for sub-shells
  11302. -#PS1="\\u@\\h:\\w "
  11303. -PS1='\u \t : \w # '
  11304. -PS2=" >"
  11305. -PS4="+ "
  11306. +#
  11307. +# /etc/profile.environment
  11308. +#
  11309. +
  11310. +# do not set interactive shell properties like HISTFILE, PS1, PS2,
  11311. +# ..., or aliases here.
  11312. +# Such stuff belongs into the startup files for *interactive* shell
  11313. +# sessions/etc/bash.bashrc or /etc/ksh.kshrc
  11314. +
  11315. +# EOF.
  11316.  
  11317. -alias vim='vi'
  11318. -alias l='ls -l'
  11319. -alias ll='ls -al'
  11320. -alias ..='cd ..'
  11321. -alias ...='cd ../..'
  11322. -alias md='mkdir'
  11323. -alias rd='rmdir'
  11324. diff --git a/ptxdist/rules/bash.in b/ptxdist/rules/bash.in
  11325. new file mode 100644
  11326. index 0000000..183c751
  11327. --- /dev/null
  11328. +++ b/ptxdist/rules/bash.in
  11329. @@ -0,0 +1,269 @@
  11330. +## SECTION=shell_and_console
  11331. +menuconfig BASH
  11332. +       tristate "bash                          "
  11333. +       select LIBC_DL
  11334. +       select GCCLIBS_GCC_S
  11335. +       select NCURSES if BASH_CURSES
  11336. +       select TERMCAP if !BASH_CURSES
  11337. +       help
  11338. +         The GNU Bourne Again SHell
  11339. +         Bash is an sh-compatible command language interpreter that executes
  11340. +         commands read from the standard input or from a file.  Bash also
  11341. +         incorporates useful features from the Korn and C shells (ksh and csh).
  11342. +
  11343. +         Bash is ultimately intended to be a conformant implementation of the
  11344. +         IEEE POSIX Shell and Tools specification (IEEE Working Group 1003.2).
  11345. +
  11346. +         Included in the bash package is the Programmable Completion Code,
  11347. +         by Ian Macdonald.
  11348. +
  11349. +         http://www.gnu.org/software/bash/
  11350. +
  11351. +if BASH
  11352. +
  11353. +config BASH_SHLIKE
  11354. +       bool
  11355. +       prompt "Enable minimal sh like configuration"
  11356. +       help
  11357. +         This produces a shell with minimal features, close to the
  11358. +         historical Bourne shell.
  11359. +
  11360. +comment ""
  11361. +       depends on INVISIBLE
  11362. +
  11363. +if !BASH_SHLIKE
  11364. +
  11365. +config BASH_ALIASES
  11366. +       bool
  11367. +       prompt "Enable aliases"
  11368. +       default y
  11369. +       help
  11370. +         Aliases allow a string to be substituted for a word
  11371. +         when it is used as the first word of a simple command.
  11372. +         The shell maintains a list of aliases that may be
  11373. +         set  and unset with the alias and unalias builtin commands
  11374. +
  11375. +config BASH_ARITHMETIC_FOR
  11376. +       bool
  11377. +       prompt "Enable arithmetic for command"
  11378. +       help
  11379. +         Include support for the alternate form of the for command that
  11380. +         behaves like the C language for statement.
  11381. +         This does not work properly in bash-2.05b!
  11382. +
  11383. +config BASH_ARRAY
  11384. +       bool
  11385. +       prompt "Include shell array variables"
  11386. +       default y
  11387. +
  11388. +config BASH_HISTORY
  11389. +       bool
  11390. +       prompt "Turn on csh-style history substitution"
  11391. +       default y
  11392. +       help
  11393. +         The bash shell supports a history expansion feature
  11394. +         that is similar to the history expansion in csh.
  11395. +
  11396. +config BASH_BRACE
  11397. +       bool
  11398. +       prompt "Include brace expansion"
  11399. +       default y
  11400. +       help
  11401. +         Brace  expansion is a mechanism by which arbitrary
  11402. +         strings may be generated.  This mechanism is similar
  11403. +         to pathname expansion, but the filenames generated
  11404. +         need not exist.
  11405. +
  11406. +config BASH_CASEMODATTR
  11407. +       bool
  11408. +       prompt "include case-modifying variable attributes"
  11409. +
  11410. +config BASH_CASEMODEXP
  11411. +       bool
  11412. +       prompt "include case-modifying word expansions"
  11413. +
  11414. +config BASH_CMDTIMING
  11415. +       bool
  11416. +       prompt "enable the time reserved word and command timing"
  11417. +
  11418. +config BASH_CONDITIONAL
  11419. +       bool
  11420. +       default y
  11421. +       prompt "Enable the conditional command"
  11422. +
  11423. +config BASH_CONDITIONAL_REGEX
  11424. +       bool
  11425. +       prompt "enable extended regular expression matching in conditional commands"
  11426. +       depends on BASH_CONDITIONAL
  11427. +
  11428. +config BASH_COPROCESSES
  11429. +       bool
  11430. +       default y
  11431. +       prompt "enable coprocess support and the coproc reserved word"
  11432. +
  11433. +config BASH_DEBUGGER
  11434. +       bool
  11435. +       prompt "enable support for bash debugger"
  11436. +
  11437. +config BASH_DIREXPDEFLT
  11438. +       bool
  11439. +       prompt "enable the direxpand shell option by default"
  11440. +
  11441. +config BASH_DIRSTACK
  11442. +       bool
  11443. +       prompt "Enable builtins pushd/popd/dirs"
  11444. +       default y
  11445. +       help
  11446. +          Without  options, "dirs" displays the list of
  11447. +          currently remembered directories.  The default
  11448. +          display is on a single line with directory
  11449. +          names separated by spaces.  Directories are
  11450. +          added to the list with the pushd command;
  11451. +          the popd command removes entries from the list.
  11452. +
  11453. +config BASH_DISABLED_BUILDINS
  11454. +       bool
  11455. +       prompt "Allow disabled builtins to still be invoked"
  11456. +
  11457. +config BASH_DPARAN_ARITH
  11458. +       bool
  11459. +       prompt "include ((...)) command"
  11460. +       default y
  11461. +
  11462. +config BASH_EXTPATTERN
  11463. +       bool
  11464. +       default y
  11465. +       # fails to build without this in 4.3.30
  11466. +       prompt "Include ksh-style extended pattern matching" if BROKEN
  11467. +
  11468. +config BASH_EXTPATTERN_DEFLT
  11469. +       bool
  11470. +       prompt "force extended pattern matching to be enabled by default"
  11471. +
  11472. +config BASH_GLOB_ASCIIRANGE_DEFLT
  11473. +       bool
  11474. +       prompt "bracket range pattern matching uses C locale"
  11475. +       help
  11476. +         force bracket range expressions in pattern matching to use the C
  11477. +         locale by default
  11478. +
  11479. +config BASH_HELP
  11480. +       bool
  11481. +       prompt "Include the help builtin"
  11482. +       help
  11483. +         This builtin supports minimal help features inside bash
  11484. +
  11485. +config BASH_CMDHISTORY
  11486. +       bool
  11487. +       prompt "Turn on command history"
  11488. +       default y
  11489. +       help
  11490. +         This enables command history features. The shell
  11491. +         buffers commands in a ringbuffer, which can be listed,
  11492. +         searched and accessed by various commands and magic
  11493. +         shell expansion features.
  11494. +
  11495. +config BASH_JOBS
  11496. +       bool
  11497. +       prompt "Enable job control features"
  11498. +       default y
  11499. +       help
  11500. +         This enables support for background jobs in bash.
  11501. +         You can list the actual managed jobs by the "jobs" command.
  11502. +
  11503. +config BASH_MULTIBYTE
  11504. +       bool
  11505. +       prompt "Enable multibyte characters"
  11506. +       default y
  11507. +       help
  11508. +         Enable multibyte characters if OS supports them.
  11509. +
  11510. +config BASH_PROCSUBST
  11511. +       bool
  11512. +       prompt "Enable process substitution"
  11513. +       default y
  11514. +       help
  11515. +         This enables process substitution if the operating system
  11516. +         provides the necessary support.
  11517. +         Process substitution is supported on systems that support
  11518. +         named pipes (FIFOs) or the '/dev/fd' method of naming open
  11519. +         files. It takes the form of <(list) or >(list).
  11520. +
  11521. +config BASH_BASHCOMPLETION
  11522. +       bool
  11523. +       prompt "Enable programmable completion"
  11524. +       help
  11525. +         Enable the programmable completion facilities.
  11526. +         When word completion is attempted for an argument to a
  11527. +         command for which a completion specification (a compspec) has
  11528. +         been defined using the complete builtin, the programmable
  11529. +         completion facilities are invoked.
  11530. +         If Readline is not enabled, this option has no effect.
  11531. +
  11532. +config BASH_ESC
  11533. +       bool
  11534. +       prompt "Turn on escape character decoding in prompts"
  11535. +       default y
  11536. +       help
  11537. +         Turn on the interpretation of a number of backslash-escaped
  11538. +         characters in the $PS1, $PS2, $PS3, and $PS4 prompt strings.
  11539. +
  11540. +config BASH_EDIT
  11541. +       bool
  11542. +#      prompt "Turn on command line editing"
  11543. +       default y
  11544. +       help
  11545. +         Include support for command-line editing and history with
  11546. +         the Bash version of the Readline library.
  11547. +
  11548. +config BASH_RESTRICTED
  11549. +       bool
  11550. +       prompt "Enable a restricted shell"
  11551. +       help
  11552. +         Include support for a restricted shell. If this is enabled,
  11553. +         Bash enters a restricted mode, when called as rbash or invoked
  11554. +         with the `--restricted' or `-r' option.
  11555. +         A restricted shell is used to set up an environment
  11556. +         more controlled than the standard shell.
  11557. +
  11558. +config BASH_SELECT
  11559. +       bool
  11560. +       prompt "Include select command"
  11561. +       help
  11562. +         Include the select builtin, which allows the generation of
  11563. +         simple menus.
  11564. +
  11565. +config BASH_SEP_HELPFILES
  11566. +       bool
  11567. +       depends on BROKEN
  11568. +       prompt "use external files for help builtin documentation"
  11569. +
  11570. +config BASH_SINGLE_HELPLINE
  11571. +       bool
  11572. +       prompt "store help documentation as a single string to ease translation"
  11573. +
  11574. +endif
  11575. +
  11576. +config BASH_GPROF
  11577. +       bool
  11578. +       prompt "Allow profiling with gprof"
  11579. +       help
  11580. +         This builds a Bash binary that produces profiling information
  11581. +         to be processed by gprof each time it is executed.
  11582. +
  11583. +config BASH_STATIC
  11584. +       bool
  11585. +       prompt "Link bash statically"
  11586. +       help
  11587. +         This causes Bash to be linked statically, if gcc is being used.
  11588. +         This could be used to build a version to use as root's shell.
  11589. +
  11590. +config BASH_CURSES
  11591. +       bool
  11592. +       prompt "Use libcurses instead of libtermcap"
  11593. +
  11594. +config BASH_SH
  11595. +       bool
  11596. +       default BUSYBOX = n || BUSYBOX_SH_IS_NONE
  11597. +
  11598. +endif
  11599. diff --git a/ptxdist/rules/bash.make b/ptxdist/rules/bash.make
  11600. new file mode 100644
  11601. index 0000000..6a1e5d7
  11602. --- /dev/null
  11603. +++ b/ptxdist/rules/bash.make
  11604. @@ -0,0 +1,111 @@
  11605. +# -*-makefile-*-
  11606. +#
  11607. +# Copyright (C) 2003-2009 by Pengutronix e.K., Hildesheim, Germany
  11608. +# For further information about the PTXdist project and license conditions
  11609. +# see the README file.
  11610. +#
  11611. +
  11612. +#
  11613. +# We provide this package
  11614. +#
  11615. +PACKAGES-$(PTXCONF_BASH) += bash
  11616. +
  11617. +#
  11618. +# Paths and names
  11619. +#
  11620. +BASH_VERSION   := 4.3.30
  11621. +BASH_MD5       := a27b3ee9be83bd3ba448c0ff52b28447
  11622. +BASH           := bash-$(BASH_VERSION)
  11623. +BASH_SUFFIX    := tar.gz
  11624. +BASH_URL       := $(call ptx/mirror, GNU, bash/$(BASH).$(BASH_SUFFIX))
  11625. +BASH_SOURCE    := $(SRCDIR)/$(BASH).$(BASH_SUFFIX)
  11626. +BASH_DIR       := $(BUILDDIR)/$(BASH)
  11627. +BASH_MAKE_PAR  := NO
  11628. +BASH_LICENSE   := GPL-3.0-or-later
  11629. +BASH_LICENSE_FILES     := \
  11630. +       file://COPYING;md5=d32239bcb673463ab874e80d47fae504 \
  11631. +       file://general.c;startline=1;endline=19;md5=c018785d21f8c206ca7a13fa7d027568
  11632. +
  11633. +# ----------------------------------------------------------------------------
  11634. +# Prepare
  11635. +# ----------------------------------------------------------------------------
  11636. +
  11637. +BASH_PATH      := PATH=$(CROSS_PATH)
  11638. +BASH_ENV       := \
  11639. +       $(CROSS_ENV) \
  11640. +       bash_cv_job_control_missing=$(call ptx/ifdef, PTXCONF_BASH_JOBS, present, missing) \
  11641. +       bash_cv_termcap_lib=$(call ptx/ifdef, PTXCONF_BASH_CURSES, libncurses, libtermcap)
  11642. +
  11643. +BASH_AUTOCONF  := \
  11644. +       $(CROSS_AUTOCONF_USR) \
  11645. +       $(GLOBAL_LARGE_FILE_OPTION) \
  11646. +       --without-bash-malloc \
  11647. +       --$(call ptx/endis, PTXCONF_BASH_SHLIKE)-minimal-config \
  11648. +       --$(call ptx/endis, PTXCONF_BASH_ALIASES)-alias \
  11649. +       --$(call ptx/endis, PTXCONF_BASH_ARITHMETIC_FOR)-arith-for-command \
  11650. +       --$(call ptx/endis, PTXCONF_BASH_ARRAY)-array-variables \
  11651. +       --$(call ptx/endis, PTXCONF_BASH_HISTORY)-bang-history \
  11652. +       --$(call ptx/endis, PTXCONF_BASH_BRACE)-brace-expansion \
  11653. +       --$(call ptx/endis, PTXCONF_BASH_CASEMODATTR)-casemod-attributes \
  11654. +       --$(call ptx/endis, PTXCONF_BASH_CASEMODEXP)-casemod-expansions \
  11655. +       --$(call ptx/endis, PTXCONF_BASH_CMDTIMING)-command-timing \
  11656. +       --$(call ptx/endis, PTXCONF_BASH_CONDITIONAL)-cond-command \
  11657. +       --$(call ptx/endis, PTXCONF_BASH_CONDITIONAL_REGEX)-cond-regexp \
  11658. +       --$(call ptx/endis, PTXCONF_BASH_COPROCESSES)-coprocesses \
  11659. +       --$(call ptx/endis, PTXCONF_BASH_DEBUGGER)-debugger \
  11660. +       --$(call ptx/endis, PTXCONF_BASH_DIREXPDEFLT)-direxpand-default \
  11661. +       --$(call ptx/endis, PTXCONF_BASH_DIRSTACK)-directory-stack \
  11662. +       --$(call ptx/endis, PTXCONF_BASH_DISABLED_BUILDINS)-disabled-builtins \
  11663. +       --$(call ptx/endis, PTXCONF_BASH_DPARAN_ARITH)-dparen-arithmetic \
  11664. +       --$(call ptx/endis, PTXCONF_BASH_EXTPATTERN)-extended-glob \
  11665. +       --$(call ptx/endis, PTXCONF_BASH_EXTPATTERN_DEFLT)-extended-glob-default \
  11666. +       --$(call ptx/endis, PTXCONF_BASH_GLOB_ASCIIRANGE_DEFLT)-glob-asciiranges-default \
  11667. +       --$(call ptx/endis, PTXCONF_BASH_HELP)-help-builtin \
  11668. +       --$(call ptx/endis, PTXCONF_BASH_CMDHISTORY)-history \
  11669. +       --$(call ptx/endis, PTXCONF_BASH_JOBS)-job-control \
  11670. +       --$(call ptx/endis, PTXCONF_BASH_MULTIBYTE)-multibyte \
  11671. +       --$(call ptx/endis, PTXCONF_BASH_PROCSUBST)-process-substitution \
  11672. +       --$(call ptx/endis, PTXCONF_BASH_BASHCOMPLETION)-progcomp \
  11673. +       --$(call ptx/endis, PTXCONF_BASH_ESC)-prompt-string-decoding \
  11674. +       --$(call ptx/endis, PTXCONF_BASH_EDIT)-readline \
  11675. +       --$(call ptx/endis, PTXCONF_BASH_RESTRICTED)-restricted \
  11676. +       --$(call ptx/endis, PTXCONF_BASH_SELECT)-select \
  11677. +       --$(call ptx/endis, PTXCONF_BASH_SEP_HELPFILES)-separate-helpfiles \
  11678. +       --$(call ptx/endis, PTXCONF_BASH_SINGLE_HELPLINE)-single-help-strings \
  11679. +       --$(call ptx/endis, PTXCONF_BASH_GPROF)-profiling \
  11680. +       --$(call ptx/endis, PTXCONF_BASH_STATIC)-static-link \
  11681. +       --$(call ptx/wwo, PTXCONF_BASH_CURSES)-curses \
  11682. +       --enable-xpg-echo-default
  11683. +
  11684. +# ----------------------------------------------------------------------------
  11685. +# Target-Install
  11686. +# ----------------------------------------------------------------------------
  11687. +
  11688. +$(STATEDIR)/bash.targetinstall:
  11689. +       @$(call targetinfo)
  11690. +
  11691. +       @$(call install_init, bash)
  11692. +       @$(call install_fixup, bash,PRIORITY,optional)
  11693. +       @$(call install_fixup, bash,SECTION,base)
  11694. +       @$(call install_fixup, bash,AUTHOR,"Robert Schwebel <r.schwebel@pengutronix.de>")
  11695. +       @$(call install_fixup, bash,DESCRIPTION,missing)
  11696. +
  11697. +# this is reverse from UNIX tradition: /usr should depend on rootfs
  11698. +# not rootfs depend on /usr
  11699. +       @$(call install_copy, bash, 0, 0, 0755, -, /usr/bin/bash)
  11700. +       @$(call install_link, bash, bash, /usr/bin/sh)
  11701. +       @$(call install_link, bash, ../usr/bin/bash, /bin/sh)
  11702. +       @$(call install_link, bash, ../usr/bin/bash, /bin/bash)
  11703. +
  11704. +# this would be the correct solution, but for some cursed issue
  11705. +# this does not work (yet)
  11706. +#      @$(call install_copy, bash, 0, 0, 0755, -, /bin/bash)
  11707. +#      @$(call install_link, bash, ./bash, /bin/sh)
  11708. +#      @$(call install_link, bash, ../../bin/bash, /usr/bin/sh)
  11709. +#      @$(call install_link, bash, ../../bin/bash, /usr/bin/bash)
  11710. +
  11711. +       @$(call install_finish, bash)
  11712. +
  11713. +       @$(call touch)
  11714. +
  11715. +# vim: syntax=make
  11716. diff --git a/ptxdist/rules/ecu01-basicsys.make b/ptxdist/rules/ecu01-basicsys.make
  11717. index 7e948b3..944432b 100644
  11718. --- a/ptxdist/rules/ecu01-basicsys.make
  11719. +++ b/ptxdist/rules/ecu01-basicsys.make
  11720. @@ -210,9 +210,10 @@ $(STATEDIR)/ecu01-basicsys.targetinstall:
  11721.         #fonts
  11722.         @$(call install_tree, ecu01-basicsys, 0, 0, $(ECU01_BASICSYS_DIR)/usr/lib/fonts, /usr/lib/fonts)
  11723.  
  11724. -       #local environment
  11725. -       @$(call install_copy, ecu01-basicsys, 0, 0, 0755, $(ECU01_BASICSYS_DIR)/etc/profile.local, \
  11726. -       /etc/profile.local)
  11727. +       #environment
  11728. +       @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/bash.bashrc, /etc/bash.bashrc)
  11729. +       @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/profile, /etc/profile)
  11730. +       @$(call install_copy, ecu01-basicsys, 0, 0, 0644, $(ECU01_BASICSYS_DIR)/etc/profile.local, /etc/profile.local)
  11731.  
  11732.         # SSH Key, Passphrase quantron-a
  11733.         @$(call install_copy, ecu01-basicsys, 0, 0, 0600, $(ECU01_BASICSYS_DIR)/etc/ssh/ecu_unix_rsa, /etc/ssh/ecu_unix_rsa)

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at