From aee3e5611a9bff915e46251df5f13384420cc3cf Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 2 Oct 2014 10:20:14 -0400 Subject: [PATCH] commit bash-20140829 snapshot --- CWRU/CWRU.chlog | 50 + CWRU/CWRU.chlog~ | 41 + CWRU/POSIX.NOTES.old | 82 + CWRU/old/set.def.save | 544 +++ CWRU/save/unwind_prot.h.save | 50 + MANIFEST | 4 + builtins/evalstring.c | 4 + cross-build/cygwin32.cache.old | 42 + doc/FAQ.orig | 1745 +++++++++ doc/aosa-bash.pdf.old | Bin 0 -> 153472 bytes doc/bash.1 | 12 +- doc/bashref.texi | 11 +- doc/version.texi | 7 +- examples/loadables/Makefile.in.save | 238 ++ execute_cmd.c | 22 +- lib/readline/doc/Makefile.old | 76 + lib/readline/history.c | 8 +- pcomplete.c | 4 + subst.h | 1 + subst.h~ | 320 ++ tests/misc/regress/log.orig | 50 + tests/misc/regress/shx.orig | 10 + tests/parser.right | 1 + tests/parser.tests | 4 + tests/parser1.sub | 1 + tests/run-parser | 2 + variables.c | 6 + variables.c~ | 5399 +++++++++++++++++++++++++++ 28 files changed, 8720 insertions(+), 14 deletions(-) create mode 100644 CWRU/POSIX.NOTES.old create mode 100644 CWRU/old/set.def.save create mode 100644 CWRU/save/unwind_prot.h.save create mode 100644 cross-build/cygwin32.cache.old create mode 100644 doc/FAQ.orig create mode 100644 doc/aosa-bash.pdf.old create mode 100644 examples/loadables/Makefile.in.save create mode 100644 lib/readline/doc/Makefile.old create mode 100644 subst.h~ create mode 100644 tests/misc/regress/log.orig create mode 100644 tests/misc/regress/shx.orig create mode 100644 tests/parser.right create mode 100644 tests/parser.tests create mode 100644 tests/parser1.sub create mode 100644 tests/run-parser create mode 100644 variables.c~ diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 4eb750c99..cc7ced6bf 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -6477,6 +6477,8 @@ execute_cmd.c recursive `eval' calls; current max is 4096 - execute_builtin: unwind-protect value of evalnest around calls to eval builtin. Suggested by Oliver Morais + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + evalnest to 0 in a subshell builtins/setattr.def - show_name_attributes: show a variable's attributes even if it's @@ -6565,3 +6567,51 @@ lib/readline/display.c - rl_message: call vsnprintf with full msg_bufsiz, since it counts one fewer than the buffer length passed as an argument. Bug report and fix from Dylan Cali + + 8/26 + ---- +builtins/evalstring.c + - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This is + instead of calling reset_parser(); that might still be needed. Fixes + bug with eval and a subsequent statement ending with EOF reported by + + +pcomplete.c + - filter_stringlist: when extglob is on, a leading ! in the filter + pattern should be left alone when it introduces a !(pat) pattern; + otherwise it messes up the pattern. Fixes bug reported by David + Korn + + 8/27 + ---- +doc/{bash.1,bashref.texi} + - clarify the behavior of bash when given the -c option, since $0 is + technically not a positional parameter. Bug reported by Stephane + Chazelas + + 8/28 + ---- +lib/readline/history.c + - add_history: use history_max_entries (if history is stifled) or + DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502) + to size the initial allocation of the history array. Assumption + is that this will reduce the number of allocations + + 8/29 + ---- +execute_command.c: + - sourcenest, sourcenest_max: new variables used to track level of + sourced files and (maybe) one day catch infinite source recursion + - execute_builtin: if current source level exceeds sourcenest_max, + trigger an error and jump back to the top level + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + sourcenest to 0 in a subshell + + 9/2 + --- +variables.c + - bind_variable: if a nameref expands to an array reference, make + sure that assign_array_element gets called (maybe even + recursively) instead of bind_variable_internal, so invalid variable + names (like arr[0]) don't get created. Fixes bug reported by + diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 4eb750c99..8ae78f5f2 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -6477,6 +6477,8 @@ execute_cmd.c recursive `eval' calls; current max is 4096 - execute_builtin: unwind-protect value of evalnest around calls to eval builtin. Suggested by Oliver Morais + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + evalnest to 0 in a subshell builtins/setattr.def - show_name_attributes: show a variable's attributes even if it's @@ -6565,3 +6567,42 @@ lib/readline/display.c - rl_message: call vsnprintf with full msg_bufsiz, since it counts one fewer than the buffer length passed as an argument. Bug report and fix from Dylan Cali + + 8/26 + ---- +builtins/evalstring.c + - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This is + instead of calling reset_parser(); that might still be needed. Fixes + bug with eval and a subsequent statement ending with EOF reported by + + +pcomplete.c + - filter_stringlist: when extglob is on, a leading ! in the filter + pattern should be left alone when it introduces a !(pat) pattern; + otherwise it messes up the pattern. Fixes bug reported by David + Korn + + 8/27 + ---- +doc/{bash.1,bashref.texi} + - clarify the behavior of bash when given the -c option, since $0 is + technically not a positional parameter. Bug reported by Stephane + Chazelas + + 8/28 + ---- +lib/readline/history.c + - add_history: use history_max_entries (if history is stifled) or + DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502) + to size the initial allocation of the history array. Assumption + is that this will reduce the number of allocations + + 8/29 + ---- +execute_command.c: + - sourcenest, sourcenest_max: new variables used to track level of + sourced files and (maybe) one day catch infinite source recursion + - execute_builtin: if current source level exceeds sourcenest_max, + trigger an error and jump back to the top level + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + sourcenest to 0 in a subshell diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old new file mode 100644 index 000000000..1707ab10c --- /dev/null +++ b/CWRU/POSIX.NOTES.old @@ -0,0 +1,82 @@ +Starting bash with the `--posix' command-line option or executing +`set -o posix' while bash is running will cause bash to conform more +closely to the Posix.2 standard by changing the behavior to match that +specified by Posix.2 in areas where the bash default differs. + +The following list is what's changed when `posix mode' is in effect: + +1. When a command in the hash table no longer exists, bash will re-search + $PATH to find the new location. This is also available with + `shopt -s checkhash'. + +2. The >& redirection does not redirect stdout and stderr. + +3. The message printed by the job control code and builtins when a job + exits with a non-zero status is `Done(status)'. + +4. Reserved words may not be aliased. + +5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and + `!!' -> `!' are enabled, and parameter expansion is performed on + the value regardless of the setting of the `promptvars' option. + +6. Interactive comments are enabled by default. (Note that bash has + them on by default anyway.) + +7. The Posix.2 startup files are executed ($ENV) rather than the normal + bash files. + +8. Tilde expansion is only performed on assignments preceding a command + name, rather than on all assignment statements on the line. + +9. The default history file is ~/.sh_history (default value of $HISTFILE). + +10. The output of `kill -l' prints all the signal names on a single line, + separated by spaces. + +11. Non-interactive shells exit if `file' in `. file' is not found. + +12. Redirection operators do not perform pathname expansion on the word + in the redirection unless the shell is interactive + +13. Function names must be valid shell identifiers. That is, they may not + contain characters other than letters, digits, and underscores, and + may not start with a digit. Declaring a function with an illegal name + causes a fatal syntax error in non-interactive shells. + +14. Posix.2 `special' builtins are found before shell functions during command + lookup. + +15. If a Posix.2 special builtin returns an error status, a non-interactive + shell exits. The fatal errors are those listed in the POSIX.2 standard, + and include things like passing incorrect options, redirection errors, + variable assignment errors for assignments preceding the command name, + and so on. + +16. The environment passed to executed commands is not sorted. Neither is + the output of `set'. This is not strictly Posix.2 behavior, but sh + does it this way. Ksh does not. It's not necessary to sort the + environment; no program should rely on it being sorted. + +17. If the `cd' builtin finds a directory to change to using $CDPATH, the + value it assigns to $PWD does not contain any symbolic links, as if + `cd -P' had been executed. + +18. A non-interactive shell exits with an error status if a variable + assignment error occurs when no command name follows the assignment + statements. A variable assignment error occurs, for example, when + trying to assign a value to a read-only variable. + +19. A non-interactive shell exits with an error status if the iteration + variable in a for statement or the selection variable in a select + statement is a read-only variable. + +20. Process substitution is not available. + +21. Assignment statements preceding POSIX.2 `special' builtins persist in + the shell environment after the builtin completes. + +There is other Posix.2 behavior that bash does not implement. Specifically: + +1. Assignment statements affect the execution environment of all builtins, + not just special ones. diff --git a/CWRU/old/set.def.save b/CWRU/old/set.def.save new file mode 100644 index 000000000..87b78d7cc --- /dev/null +++ b/CWRU/old/set.def.save @@ -0,0 +1,544 @@ +This file is set.def, from which is created set.c. +It implements the "set" and "unset" builtins in Bash. + +Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GNU Bash, the Bourne Again SHell. + +Bash is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 1, or (at your option) any later +version. + +Bash is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with Bash; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +$PRODUCES set.c + +#include +#include "../shell.h" +#include "../flags.h" + +#include "bashgetopt.h" + +extern int interactive; +extern int noclobber, posixly_correct; +#if defined (READLINE) +extern int rl_editing_mode, no_line_editing; +#endif /* READLINE */ + +$BUILTIN set +$FUNCTION set_builtin +$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...] + -a Mark variables which are modified or created for export. + -b Notify of job termination immediately. + -e Exit immediately if a command exits with a non-zero status. + -f Disable file name generation (globbing). + -h Locate and remember function commands as functions are + defined. Function commands are normally looked up when + the function is executed. + -i Force the shell to be an "interactive" one. Interactive shells + always read `~/.bashrc' on startup. + -k All keyword arguments are placed in the environment for a + command, not just those that precede the command name. + -m Job control is enabled. + -n Read commands but do not execute them. + -o option-name + Set the variable corresponding to option-name: + allexport same as -a + braceexpand same as -B +#if defined (READLINE) + emacs use an emacs-style line editing interface +#endif /* READLINE */ + errexit same as -e + histexpand same as -H + ignoreeof the shell will not exit upon reading EOF + interactive-comments + allow comments to appear in interactive commands + monitor same as -m + noclobber disallow redirection to existing files + noexec same as -n + noglob same as -f + nohash same as -d + notify save as -b + nounset same as -u + physical same as -P + posix change the behavior of bash where the default + operation differs from the 1003.2 standard to + match the standard + privileged same as -p + verbose same as -v +#if defined (READLINE) + vi use a vi-style line editing interface +#endif /* READLINE */ + xtrace same as -x + -p Turned on whenever the real and effective user ids do not match. + Disables processing of the $ENV file and importing of shell + functions. Turning this option off causes the effective uid and + gid to be set to the real uid and gid. + -t Exit after reading and executing one command. + -u Treat unset variables as an error when substituting. + -v Print shell input lines as they are read. + -x Print commands and their arguments as they are executed. + -l Save and restore the binding of the NAME in a FOR command. + -d Disable the hashing of commands that are looked up for execution. + Normally, commands are remembered in a hash table, and once + found, do not have to be looked up again. +#if defined (BRACE_EXPANSION) + -B the shell will perform brace expansion +#endif /* BRACE_EXPANSION */ +#if defined (BANG_HISTORY) + -H Enable ! style history substitution. This flag is on + by default. +#endif /* BANG_HISTORY */ + -C If set, disallow existing regular files to be overwritten + by redirection of output. + -P If set, do not follow symbolic links when executing commands + such as cd which change the current directory. + +Using + rather than - causes these flags to be turned off. The +flags can also be used upon invocation of the shell. The current +set of flags may be found in $-. The remaining n ARGs are positional +parameters and are assigned, in order, to $1, $2, .. $n. If no +ARGs are given, all shell variables are printed. +$END + +/* An a-list used to match long options for set -o to the corresponding + option letter. */ +struct { + char *name; + int letter; +} o_options[] = { + { "allexport", 'a' }, +#if defined (BRACE_EXPANSION) + { "braceexpand",'B' }, +#endif + { "errexit", 'e' }, + { "histexpand", 'H' }, + { "monitor", 'm' }, + { "noexec", 'n' }, + { "noglob", 'f' }, + { "nohash", 'd' }, +#if defined (JOB_CONTROL) + { "notify", 'b' }, +#endif /* JOB_CONTROL */ + {"nounset", 'u' }, + {"physical", 'P' }, + {"privileged", 'p' }, + {"verbose", 'v' }, + {"xtrace", 'x' }, + {(char *)NULL, 0}, +}; + +#define MINUS_O_FORMAT "%-15s\t%s\n" + +void +list_minus_o_opts () +{ + register int i; + char *on = "on", *off = "off"; + + printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); + + if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) + printf (MINUS_O_FORMAT, "ignoreeof", on); + else + printf (MINUS_O_FORMAT, "ignoreeof", off); + + printf (MINUS_O_FORMAT, "interactive-comments", + interactive_comments ? on : off); + + printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); + +#if defined (READLINE) + if (no_line_editing) + { + printf (MINUS_O_FORMAT, "emacs", off); + printf (MINUS_O_FORMAT, "vi", off); + } + else + { + /* Magic. This code `knows' how readline handles rl_editing_mode. */ + printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off); + printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off); + } +#endif /* READLINE */ + + for (i = 0; o_options[i].name; i++) + { + int *on_or_off, zero = 0; + + on_or_off = find_flag (o_options[i].letter); + if (on_or_off == FLAG_UNKNOWN) + on_or_off = &zero; + printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off); + } +} + +set_minus_o_option (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + int option_char = -1; + + if (STREQ (option_name, "noclobber")) + { + if (on_or_off == FLAG_ON) + bind_variable ("noclobber", ""); + else + unbind_variable ("noclobber"); + stupidly_hack_special_variables ("noclobber"); + } + else if (STREQ (option_name, "ignoreeof")) + { + unbind_variable ("ignoreeof"); + unbind_variable ("IGNOREEOF"); + if (on_or_off == FLAG_ON) + bind_variable ("IGNOREEOF", "10"); + stupidly_hack_special_variables ("IGNOREEOF"); + } + +#if defined (READLINE) + else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) + { + if (on_or_off == FLAG_ON) + { + rl_variable_bind ("editing-mode", option_name); + + if (interactive) + with_input_from_stdin (); + no_line_editing = 0; + } + else + { + int isemacs = (rl_editing_mode == 1); + if ((isemacs && STREQ (option_name, "emacs")) || + (!isemacs && STREQ (option_name, "vi"))) + { + if (interactive) + with_input_from_stream (stdin, "stdin"); + no_line_editing = 1; + } + else + builtin_error ("not in %s editing mode", option_name); + } + } +#endif /* READLINE */ + else if (STREQ (option_name, "interactive-comments")) + interactive_comments = (on_or_off == FLAG_ON); + else if (STREQ (option_name, "posix")) + { + posixly_correct = (on_or_off == FLAG_ON); + unbind_variable ("POSIXLY_CORRECT"); + unbind_variable ("POSIX_PEDANTIC"); + if (on_or_off == FLAG_ON) + { + bind_variable ("POSIXLY_CORRECT", ""); + stupidly_hack_special_variables ("POSIXLY_CORRECT"); + } + } + else + { + register int i; + for (i = 0; o_options[i].name; i++) + { + if (STREQ (option_name, o_options[i].name)) + { + option_char = o_options[i].letter; + break; + } + } + if (option_char == -1) + { + builtin_error ("%s: unknown option name", option_name); + return (EXECUTION_FAILURE); + } + if (change_flag (option_char, on_or_off) == FLAG_ERROR) + { + bad_option (option_name); + return (EXECUTION_FAILURE); + } + } + return (EXECUTION_SUCCESS); +} + +/* Set some flags from the word values in the input list. If LIST is empty, + then print out the values of the variables instead. If LIST contains + non-flags, then set $1 - $9 to the successive words of LIST. */ +set_builtin (list) + WORD_LIST *list; +{ + int on_or_off, flag_name, force_assignment = 0; + + if (!list) + { + SHELL_VAR **vars; + + vars = all_shell_variables (); + if (vars) + { + print_var_list (vars); + free (vars); + } + + vars = all_shell_functions (); + if (vars) + { + print_var_list (vars); + free (vars); + } + + return (EXECUTION_SUCCESS); + } + + /* Check validity of flag arguments. */ + if (*list->word->word == '-' || *list->word->word == '+') + { + register char *arg; + WORD_LIST *save_list = list; + + while (list && (arg = list->word->word)) + { + char c; + + if (arg[0] != '-' && arg[0] != '+') + break; + + /* `-' or `--' signifies end of flag arguments. */ + if (arg[0] == '-' && + (!arg[1] || (arg[1] == '-' && !arg[2]))) + break; + + while (c = *++arg) + { + if (find_flag (c) == FLAG_UNKNOWN && c != 'o') + { + char s[2]; + s[0] = c; s[1] = '\0'; + bad_option (s); + if (c == '?') + builtin_usage (); + return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + } + } + list = list->next; + } + list = save_list; + } + + /* Do the set command. While the list consists of words starting with + '-' or '+' treat them as flags, otherwise, start assigning them to + $1 ... $n. */ + while (list) + { + char *string = list->word->word; + + /* If the argument is `--' or `-' then signal the end of the list + and remember the remaining arguments. */ + if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2]))) + { + list = list->next; + + /* `set --' unsets the positional parameters. */ + if (string[1] == '-') + force_assignment = 1; + + /* Until told differently, the old shell behaviour of + `set - [arg ...]' being equivalent to `set +xv [arg ...]' + stands. Posix.2 says the behaviour is marked as obsolescent. */ + else + { + change_flag ('x', '+'); + change_flag ('v', '+'); + } + + break; + } + + if ((on_or_off = *string) && + (on_or_off == '-' || on_or_off == '+')) + { + int i = 1; + while (flag_name = string[i++]) + { + if (flag_name == '?') + { + builtin_usage (); + return (EXECUTION_SUCCESS); + } + else if (flag_name == 'o') /* -+o option-name */ + { + char *option_name; + WORD_LIST *opt; + + opt = list->next; + + if (!opt) + { + list_minus_o_opts (); + continue; + } + + option_name = opt->word->word; + + if (!option_name || !*option_name || (*option_name == '-')) + { + list_minus_o_opts (); + continue; + } + list = list->next; /* Skip over option name. */ + + if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS) + return (EXECUTION_FAILURE); + } + else + { + if (change_flag (flag_name, on_or_off) == FLAG_ERROR) + { + char opt[3]; + opt[0] = on_or_off; + opt[1] = flag_name; + opt[2] = '\0'; + bad_option (opt); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + } + } + else + { + break; + } + list = list->next; + } + + /* Assigning $1 ... $n */ + if (list || force_assignment) + remember_args (list, 1); + return (EXECUTION_SUCCESS); +} + +$BUILTIN unset +$FUNCTION unset_builtin +$SHORT_DOC unset [-f] [-v] [name ...] +For each NAME, remove the corresponding variable or function. Given +the `-v', unset will only act on variables. Given the `-f' flag, +unset will only act on functions. With neither flag, unset first +tries to unset a variable, and if that fails, then tries to unset a +function. Some variables (such as PATH and IFS) cannot be unset; also +see readonly. +$END + +#define NEXT_VARIABLE() any_failed++; list = list->next; continue; + +unset_builtin (list) + WORD_LIST *list; +{ + int unset_function, unset_variable, unset_array, opt, any_failed; + char *name; + + unset_function = unset_variable = unset_array = any_failed = 0; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "fv")) != -1) + { + switch (opt) + { + case 'f': + unset_function = 1; + break; + case 'v': + unset_variable = 1; + break; + default: + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + + list = loptend; + + if (unset_function && unset_variable) + { + builtin_error ("cannot simultaneously unset a function and a variable"); + return (EXECUTION_FAILURE); + } + + while (list) + { + SHELL_VAR *var; + int tem; +#if defined (ARRAY_VARS) + char *t; +#endif + + name = list->word->word; + +#if defined (ARRAY_VARS) + if (!unset_function && valid_array_reference (name)) + { + t = strchr (name, '['); + *t++ = '\0'; + unset_array++; + } +#endif + + var = unset_function ? find_function (name) : find_variable (name); + + if (var && !unset_function && non_unsettable_p (var)) + { + builtin_error ("%s: cannot unset", name); + NEXT_VARIABLE (); + } + + /* Posix.2 says that unsetting readonly variables is an error. */ + if (var && readonly_p (var)) + { + builtin_error ("%s: cannot unset: readonly %s", + name, unset_function ? "function" : "variable"); + NEXT_VARIABLE (); + } + + /* Unless the -f option is supplied, the name refers to a variable. */ +#if defined (ARRAY_VARS) + if (var && unset_array) + { + if (array_p (var) == 0) + { + builtin_error ("%s: not an array variable", name); + NEXT_VARIABLE (); + } + else + tem = unbind_array_element (var, t); + } + else +#endif /* ARRAY_VARS */ + tem = makunbound (name, unset_function ? shell_functions : shell_variables); + + /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v + is specified, the name refers to a variable; if a variable by + that name does not exist, a function by that name, if any, + shall be unset.'' */ + if ((tem == -1) && !unset_function && !unset_variable) + tem = makunbound (name, shell_functions); + + if (tem == -1) + any_failed++; + else if (!unset_function) + stupidly_hack_special_variables (name); + + list = list->next; + } + + if (any_failed) + return (EXECUTION_FAILURE); + else + return (EXECUTION_SUCCESS); +} diff --git a/CWRU/save/unwind_prot.h.save b/CWRU/save/unwind_prot.h.save new file mode 100644 index 000000000..998fd72b6 --- /dev/null +++ b/CWRU/save/unwind_prot.h.save @@ -0,0 +1,50 @@ +/* unwind_prot.h - Macros and functions for hacking unwind protection. */ + +/* Copyright (C) 1993 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_UNWIND_PROT_H) +#define _UNWIND_PROT_H + +/* Run a function without interrupts. */ +extern void begin_unwind_frame (); +extern void discard_unwind_frame (); +extern void run_unwind_frame (); +extern void add_unwind_protect (); +extern void remove_unwind_protect (); +extern void run_unwind_protects (); +extern void unwind_protect_var (); + +/* Define for people who like their code to look a certain way. */ +#define end_unwind_frame() + +/* How to protect an integer. */ +#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int)) + +/* How to protect a pointer to a string. */ +#define unwind_protect_string(X) \ + unwind_protect_var ((int *)&(X), (X), sizeof (char *)) + +/* How to protect any old pointer. */ +#define unwind_protect_pointer(X) unwind_protect_string (X) + +/* How to protect the contents of a jmp_buf. */ +#define unwind_protect_jmp_buf(X) \ + unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t)) + +#endif /* _UNWIND_PROT_H */ diff --git a/MANIFEST b/MANIFEST index eae9e1cbf..d81c68d62 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1051,6 +1051,9 @@ tests/nquote4.tests f tests/nquote4.right f tests/nquote5.tests f tests/nquote5.right f +tests/parser.tests f +tests/parser.right f +tests/parser1.sub f tests/posix2.tests f tests/posix2.right f tests/posixexp.tests f @@ -1157,6 +1160,7 @@ tests/run-nquote2 f tests/run-nquote3 f tests/run-nquote4 f tests/run-nquote5 f +tests/run-parser f tests/run-posix2 f tests/run-posixexp f tests/run-posixexp2 f diff --git a/builtins/evalstring.c b/builtins/evalstring.c index ce5b4d63d..85ad985f5 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -226,6 +226,10 @@ parse_and_execute (string, from_file, flags) code = should_jump_to_top_level = 0; last_result = EXECUTION_SUCCESS; + /* We need to reset enough of the token state so we can start fresh. */ + if (current_token == yacc_EOF) + current_token = '\n'; /* reset_parser() ? */ + with_input_from_string (string, from_file); while (*(bash_input.location.string)) { diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old new file mode 100644 index 000000000..640390fbf --- /dev/null +++ b/cross-build/cygwin32.cache.old @@ -0,0 +1,42 @@ +# This file is a shell script that caches the results of configure +# tests for CYGWIN32 so they don't need to be done when cross-compiling. + +# AC_FUNC_GETPGRP should also define GETPGRP_VOID +ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} +# AC_FUNC_SETVBUF_REVERSED should not define anything else +ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} +# on CYGWIN32, system calls do not restart +ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} +bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} + +# these may be necessary, but they are currently commented out +#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} +ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} +ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} +ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} +ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} + +bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} +bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} +bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} +bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} +bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} +bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} +bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} +bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} +bash_cv_printf_declared=${bash_cv_printf_declared='yes'} +bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} +bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} +bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} +bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} +bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} +bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} +bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} +bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} + +bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} +bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} + +ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} + +# end of cross-build/cygwin32.cache diff --git a/doc/FAQ.orig b/doc/FAQ.orig new file mode 100644 index 000000000..1cff3c8ef --- /dev/null +++ b/doc/FAQ.orig @@ -0,0 +1,1745 @@ +This is the Bash FAQ, version 3.24, for Bash version 2.05b. + +This document contains a set of frequently-asked questions concerning +Bash, the GNU Bourne-Again Shell. Bash is a freely-available command +interpreter with advanced features for both interactive use and shell +programming. + +Another good source of basic information about shells is the collection +of FAQ articles periodically posted to comp.unix.shell. + +Questions and comments concerning this document should be sent to +chet@po.cwru.edu. + +This document is available for anonymous FTP with the URL + +ftp://ftp.cwru.edu/pub/bash/FAQ + +The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html + +---------- +Contents: + +Section A: The Basics + +A1) What is it? +A2) What's the latest version? +A3) Where can I get it? +A4) On what machines will bash run? +A5) Will bash run on operating systems other than Unix? +A6) How can I build bash with gcc? +A7) How can I make bash my login shell? +A8) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? +A9) What's the `POSIX 1003.2 standard'? +A10) What is the bash `posix mode'? + +Section B: The latest version + +B1) What's new in version 2.05b? +B2) Are there any user-visible incompatibilities between bash-2.05b and + bash-1.14.7? + +Section C: Differences from other Unix shells + +C1) How does bash differ from sh, the Bourne shell? +C2) How does bash differ from the Korn shell, version ksh88? +C3) Which new features in ksh-93 are not in bash, and which are? + +Section D: Why does bash do some things differently than other Unix shells? + +D1) Why does bash run a different version of `command' than + `which command' says it will? +D2) Why doesn't bash treat brace expansions exactly like csh? +D3) Why doesn't bash have csh variable modifiers? +D4) How can I make my csh aliases work when I convert to bash? +D5) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? +D6) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +Section E: Why does bash do certain things the way it does? + +E1) Why is the bash builtin `test' slightly different from /bin/test? +E2) Why does bash sometimes say `Broken pipe'? +E3) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? +E4) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? +E5) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? +E6) Why doesn't a while or for loop get suspended when I type ^Z? +E7) What about empty for loops in Makefiles? +E8) Why does the arithmetic evaluation code complain about `08'? +E9) Why does the pattern matching expression [A-Z]* match files beginning + with every letter except `z'? +E10) Why does `cd //' leave $PWD as `//'? +E11) If I resize my xterm while another program is running, why doesn't bash + notice the change? + +Section F: Things to watch out for on certain Unix versions + +F1) Why can't I use command line editing in my `cmdtool'? +F2) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? +F3) Why does bash dump core after I interrupt username completion or + `~user' tilde expansion on a machine running NIS? +F4) I'm running SVR4.2. Why is the line erased every time I type `@'? +F5) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? +F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? +F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on + HP/UX 11.x? + +Section G: How can I get bash to do certain common things? + +G1) How can I get bash to read and display eight-bit characters? +G2) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? +G3) How can I find the value of a shell variable whose name is the value + of another shell variable? +G4) How can I make the bash `time' reserved word print timing output that + looks like the output from my system's /usr/bin/time? +G5) How do I get the current directory into my prompt? +G6) How can I rename "*.foo" to "*.bar"? +G7) How can I translate a filename from uppercase to lowercase? +G8) How can I write a filename expansion (globbing) pattern that will match + all files in the current directory except "." and ".."? + +Section H: Where do I go from here? + +H1) How do I report bugs in bash, and where should I look for fixes and + advice? +H2) What kind of bash documentation is there? +H3) What's coming in future versions? +H4) What's on the bash `wish list'? +H5) When will the next release appear? + +---------- +Section A: The Basics + +A1) What is it? + +Bash is a Unix command interpreter (shell). It is an implementation of +the Posix 1003.2 shell standard, and resembles the Korn and System V +shells. + +Bash contains a number of enhancements over those shells, both +for interactive use and shell programming. Features geared +toward interactive use include command line editing, command +history, job control, aliases, and prompt expansion. Programming +features include additional variable expansions, shell +arithmetic, and a number of variables and options to control +shell behavior. + +Bash was originally written by Brian Fox of the Free Software +Foundation. The current developer and maintainer is Chet Ramey +of Case Western Reserve University. + +A2) What's the latest version? + +The latest version is 2.05b, first made available on Wednesday, 17 +July, 2002. + +A3) Where can I get it? + +Bash is the GNU project's shell, and so is available from the +master GNU archive site, ftp.gnu.org, and its mirrors. The +latest version is also available for FTP from ftp.cwru.edu. +The following URLs tell how to get version 2.05b: + +ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz + +Formatted versions of the documentation are available with the URLs: + +ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz + +A4) On what machines will bash run? + +Bash has been ported to nearly every version of UNIX. All you +should have to do to build it on a machine for which a port +exists is to type `configure' and then `make'. The build process +will attempt to discover the version of UNIX you have and tailor +itself accordingly, using a script created by GNU autoconf. + +More information appears in the file `INSTALL' in the distribution. + +The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) +explains how to obtain binary versions of bash for most of the major +commercial Unix systems. + +A5) Will bash run on operating systems other than Unix? + +Configuration specifics for Unix-like systems such as QNX and +LynxOS are included in the distribution. Bash-2.05 and later +versions should compile and run on Minix 2.0 (patches were +contributed), but I don't believe anyone has built bash-2.x on +earlier Minix versions yet. + +Bash has been ported to versions of Windows implementing the Win32 +programming interface. This includes Windows 95 and Windows NT. +The port was done by Cygnus Solutions as part of their CYGWIN +project. For more information about the project, look at the URLs + +http://www.cygwin.com/ +http://sourceware.cygnus.com/cygwin + +Cygnus originally ported bash-1.14.7, and that port was part of their +early GNU-Win32 (the original name) releases. Cygnus has also done a +port of bash-2.05 to the CYGWIN environment, and it is available as +part of their current release. + +Bash-2.05b should require no local Cygnus changes to build and run under +CYGWIN. + +The Cygnus port works only on Intel machines. There is a port of bash +(I don't know which version) to the alpha/NT environment available from + +ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz + +DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part +of the DJGPP project. For more information on the project, see + +http://www.delorie.com/djgpp/ + +I have been told that the original DJGPP port was done by Daisuke Aoyama. + +Mark Elbrecht has sent me notice that bash-2.04 +is available for DJGPP V2. The files are available as: + +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation +ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source + +Mark has begun to work with bash-2.05, but I don't know the status. + +Ports of bash-1.12 and bash-2.0 are available for OS/2 from + +ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip +ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip + +I haven't looked at either, but the second appears to be a binary-only +distribution. Beware. + +I have received word that Bash (I'm not sure which version, but I +believe that it's at least bash-2.02.1) is the standard shell on +BeOS. + +A6) How can I build bash with gcc? + +Bash configures to use gcc by default if it is available. Read the +file INSTALL in the distribution for more information. + +A7) How can I make bash my login shell? + +Some machines let you use `chsh' to change your login shell. Other +systems use `passwd -s' or `passwd -e'. If one of these works for +you, that's all you need. Note that many systems require the full +pathname to a shell to appear in /etc/shells before you can make it +your login shell. For this, you may need the assistance of your +friendly local system administrator. + +If you cannot do this, you can still use bash as your login shell, but +you need to perform some tricks. The basic idea is to add a command +to your login shell's startup file to replace your login shell with +bash. + +For example, if your login shell is csh or tcsh, and you have installed +bash in /usr/gnu/bin/bash, add the following line to ~/.login: + + if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login + +(the `--login' tells bash that it is a login shell). + +It's not a good idea to put this command into ~/.cshrc, because every +csh you run without the `-f' option, even ones started to run csh scripts, +reads that file. If you must put the command in ~/.cshrc, use something +like + + if ( $?prompt ) exec /usr/gnu/bin/bash --login + +to ensure that bash is exec'd only when the csh is interactive. + +If your login shell is sh or ksh, you have to do two things. + +First, create an empty file in your home directory named `.bash_profile'. +The existence of this file will prevent the exec'd bash from trying to +read ~/.profile, and re-execing itself over and over again. ~/.bash_profile +is the first file bash tries to read initialization commands from when +it is invoked as a login shell. + +Next, add a line similar to the above to ~/.profile: + + [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ + exec /usr/gnu/bin/bash --login + +This will cause login shells to replace themselves with bash running as +a login shell. Once you have this working, you can copy your initialization +code from ~/.profile to ~/.bash_profile. + +I have received word that the recipe supplied above is insufficient for +machines running CDE. CDE has a maze of twisty little startup files, all +slightly different. + +If you cannot change your login shell in the password file to bash, you +will have to (apparently) live with CDE using the shell in the password +file to run its startup scripts. If you have changed your shell to bash, +there is code in the CDE startup files (on Solaris, at least) that attempts +to do the right thing. It is, however, often broken, and may require that +you use the $BASH_ENV trick described below. + +`dtterm' claims to use $SHELL as the default program to start, so if you +can change $SHELL in the CDE startup files, you should be able to use bash +in your terminal windows. + +Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program +to read your login shell's startup files. You may be able to use bash for +the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as +well, but I have not tried this. + +You can use the above `exec' recipe to start bash when not logging in with +CDE by testing the value of the DT variable: + + if [ -n "$DT" ]; then + [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login + fi + +If CDE starts its shells non-interactively during login, the login shell +startup files (~/.profile, ~/.bash_profile) will not be sourced at login. +To get around this problem, append a line similar to the following to your +~/.dtprofile: + + BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV + +and add the following line to the beginning of ~/.bash_profile: + + unset BASH_ENV + +A8) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? + +You must add the full pathname to bash to the file /etc/shells. As +noted in the answer to the previous question, many systems require +this before you can make bash your login shell. + +Most versions of ftpd use this file to prohibit `special' users +such as `uucp' and `news' from using FTP. + +A9) What's the `POSIX 1003.2 standard'? + +POSIX is a name originally coined by Richard Stallman for a +family of open system standards based on UNIX. There are a +number of aspects of UNIX under consideration for +standardization, from the basic system services at the system +call and C library level to applications and tools to system +administration and management. Each area of standardization is +assigned to a working group in the 1003 series. + +The POSIX Shell and Utilities standard has been developed by IEEE +Working Group 1003.2 (POSIX.2). It concentrates on the command +interpreter interface and utility programs commonly executed from +the command line or by other programs. An initial version of the +standard has been approved and published by the IEEE, and work is +currently underway to update it. + +Bash is concerned with the aspects of the shell's behavior +defined by POSIX.2. The shell command language has of course +been standardized, including the basic flow control and program +execution constructs, I/O redirection and pipelining, argument +handling, variable expansion, and quoting. + +The `special' builtins, which must be implemented as part of the +shell to provide the desired functionality, are specified as +being part of the shell; examples of these are `eval' and +`export'. Other utilities appear in the sections of POSIX.2 not +devoted to the shell which are commonly (and in some cases must +be) implemented as builtin commands, such as `read' and `test'. +POSIX.2 also specifies aspects of the shell's interactive +behavior as part of the UPE, including job control and command +line editing. Only vi-style line editing commands have been +standardized; emacs editing commands were left out due to +objections. + +The Open Group has made an older version of its Single Unix +Specification (version 2), which is very similar to POSIX.2, +available on the web at + +http://www.opengroup.org/onlinepubs/007908799/ + +The Single Unix Specification, version 3, is available on the web at + +http://www.opengroup.org/onlinepubs/007904975/ + +A10) What is the bash `posix mode'? + +Although bash is an implementation of the POSIX.2 shell +specification, there are areas where the bash default behavior +differs from that spec. The bash `posix mode' changes the bash +behavior in these areas so that it obeys the spec more closely. + +Posix mode is entered by starting bash with the --posix or +'-o posix' option or executing `set -o posix' after bash is running. + +The specific aspects of bash which change when posix mode is +active are listed in the file POSIX in the bash distribution. +They are also listed in a section in the Bash Reference Manual +(from which that file is generated). + +Section B: The latest version + +B1) What's new in version 2.05b? + +The raison d'etre for bash-2.05b is to make a second intermediate +release containing the first of the new features to be available +in bash-3.0 and get feedback on those features before proceeding. +The major new feature is multibyte character support in both Bash +and Readline. + +Bash-2.05b contains the following new features (see the manual page for +complete descriptions and the CHANGES and NEWS files in the bash-2.05b +distribution): + +o support for multibyte characters has been added to both bash and readline + +o the DEBUG trap is now run *before* simple commands, ((...)) commands, + [[...]] conditional commands, and for ((...)) loops + +o the shell now performs arithmetic in the largest integer size the machine + supports (intmax_t) + +o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) + and inserts the result into the expanded prompt + +o there is a new `here-string' redirection operator: <<< word + +o when displaying variables, function attributes and definitions are shown + separately, allowing them to be re-used as input (attempting to re-use + the old output would result in syntax errors). + +o `read' has a new `-u fd' option to read from a specified file descriptor + +o the bash debugger in examples/bashdb has been modified to work with the + new DEBUG trap semantics, the command set has been made more gdb-like, + and the changes to $LINENO make debugging functions work better + +o the expansion of $LINENO inside a shell function is only relative to the + function start if the shell is interactive -- if the shell is running a + script, $LINENO expands to the line number in the script. This is as + POSIX-2001 requires + + +A short feature history dating from Bash-2.0: + +Bash-2.05a introduced the following new features: + +o The `printf' builtin has undergone major work + +o There is a new read-only `shopt' option: login_shell, which is set by + login shells and unset otherwise + +o New `\A' prompt string escape sequence; expanding to time in 24-hour + HH:MM format + +o New `-A group/-g' option to complete and compgen; goes group name + completion + +o New [+-]O invocation option to set and unset `shopt' options at startup + +o ksh-like `ERR' trap + +o `for' loops now allow empty word lists after the `in' reserved word + +o new `hard' and `soft' arguments for the `ulimit' builtin + +o Readline can be configured to place the user at the same point on the line + when retrieving commands from the history list + +o Readline can be configured to skip `hidden' files (filenames with a leading + `.' on Unix) when performing completion + +Bash-2.05 introduced the following new features: + +o This version has once again reverted to using locales and strcoll(3) when + processing pattern matching bracket expressions, as POSIX requires. +o Added a new `--init-file' invocation argument as a synonym for `--rcfile', + per the new GNU coding standards. +o The /dev/tcp and /dev/udp redirections now accept service names as well as + port numbers. +o `complete' and `compgen' now take a `-o value' option, which controls some + of the aspects of that compspec. Valid values are: + + default - perform bash default completion if programmable + completion produces no matches + dirnames - perform directory name completion if programmable + completion produces no matches + filenames - tell readline that the compspec produces filenames, + so it can do things like append slashes to + directory names and suppress trailing spaces +o A new loadable builtin, realpath, which canonicalizes and expands symlinks + in pathname arguments. +o When `set' is called without options, it prints function defintions in a + way that allows them to be reused as input. This affects `declare' and + `declare -p' as well. This only happens when the shell is not in POSIX + mode, since POSIX.2 forbids this behavior. + +Bash-2.04 introduced the following new features: + +o Programmable word completion with the new `complete' and `compgen' builtins; + examples are provided in examples/complete/complete-examples +o `history' has a new `-d' option to delete a history entry +o `bind' has a new `-x' option to bind key sequences to shell commands +o The prompt expansion code has new `\j' and `\l' escape sequences +o The `no_empty_cmd_completion' shell option, if enabled, inhibits + command completion when TAB is typed on an empty line +o `help' has a new `-s' option to print a usage synopsis +o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) +o New ksh93-style arithmetic for command: + for ((expr1 ; expr2; expr3 )); do list; done +o `read' has new options: `-t', `-n', `-d', `-s' +o The redirection code handles several filenames specially: /dev/fd/N, + /dev/stdin, /dev/stdout, /dev/stderr +o The redirection code now recognizes /dev/tcp/HOST/PORT and + /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, + to the specified port on the specified host +o The ${!prefix*} expansion has been implemented +o A new FUNCNAME variable, which expands to the name of a currently-executing + function +o The GROUPS variable is no longer readonly +o A new shopt `xpg_echo' variable, to control the behavior of echo with + respect to backslash-escape sequences at runtime +o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned + +The version of Readline released with Bash-2.04, Readline-4.1, had several +new features as well: + +o Parentheses matching is always compiled into readline, and controllable + with the new `blink-matching-paren' variable +o The history-search-forward and history-search-backward functions now leave + point at the end of the line when the search string is empty, like + reverse-search-history, and forward-search-history +o A new function for applications: rl_on_new_line_with_prompt() +o New variables for applications: rl_already_prompted, and rl_gnu_readline_p + + +Bash-2.03 had very few new features, in keeping with the convention +that odd-numbered releases provide mainly bug fixes. A number of new +features were added to Readline, mostly at the request of the Cygnus +folks. + +A new shopt option, `restricted_shell', so that startup files can test + whether or not the shell was started in restricted mode +Filename generation is now performed on the words between ( and ) in + compound array assignments (this is really a bug fix) +OLDPWD is now auto-exported, as POSIX.2 requires +ENV and BASH_ENV are read-only variables in a restricted shell +Bash may now be linked against an already-installed Readline library, + as long as the Readline library is version 4 or newer +All shells begun with the `--login' option will source the login shell + startup files, even if the shell is not interactive + +There were lots of changes to the version of the Readline library released +along with Bash-2.03. For a complete list of the changes, read the file +CHANGES in the Bash-2.03 distribution. + +Bash-2.02 contained the following new features: + +a new version of malloc (based on the old GNU malloc code in previous + bash versions) that is more page-oriented, more conservative + with memory usage, does not `orphan' large blocks when they + are freed, is usable on 64-bit machines, and has allocation + checking turned on unconditionally +POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) +POSIX.2-style globbing equivalence classes +POSIX.2-style globbing collating symbols +the ksh [[...]] extended conditional command +the ksh egrep-style extended pattern matching operators +a new `printf' builtin +the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- + prompt string special char translation and variable expansion + auto-export of variables in initial environment + command search finds functions before builtins + bash return builtin will exit a file sourced with `.' + builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. + export -n/-f/-p/name=value, pwd -L/-P, + read -e/-p/-a/-t/-n/-d/-s/-u, + readonly -a/-f/name=value, trap -l, set +o, + set -b/-m/-o option/-h/-p/-B/-C/-H/-P, + unset -f/-v, ulimit -m/-p/-u, + type -a/-p/-t/-f/-P, suspend -f, kill -n, + test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S + bash reads ~/.bashrc for interactive shells, $ENV for non-interactive + bash restricted shell mode is more extensive + bash allows functions and variables with the same name + brace expansion + tilde expansion + arithmetic expansion with $((...)) and `let' builtin + the `[[...]]' extended conditional command + process substitution + aliases and alias/unalias builtins + local variables in functions and `local' builtin + readline and command-line editing with programmable completion + command history and history/fc builtins + csh-like history expansion + other new bash builtins: bind, command, compgen, complete, builtin, + declare/typeset, dirs, enable, fc, help, + history, logout, popd, pushd, disown, shopt, + printf + exported functions + filename generation when using output redirection (command >a*) + POSIX.2-style globbing character classes + POSIX.2-style globbing equivalence classes + POSIX.2-style globbing collating symbols + egrep-like extended pattern matching operators + case-insensitive pattern matching and globbing + variable assignments preceding commands affect only that command, + even for builtins and functions + posix mode + redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, + /dev/tcp/host/port, /dev/udp/host/port + +Things sh has that bash does not: + uses variable SHACCT to do shell accounting + includes `stop' builtin (bash can use alias stop='kill -s STOP') + `newgrp' builtin + turns on job control if called as `jsh' + $TIMEOUT (like bash $TMOUT) + `^' is a synonym for `|' + new SVR4.2 sh builtins: mldmode, priv + +Implementation differences: + redirection to/from compound commands causes sh to create a subshell + bash does not allow unbalanced quotes; sh silently inserts them at EOF + bash does not mess with signal 11 + sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 + bash splits only the results of expansions on IFS, using POSIX.2 + field splitting rules; sh splits all words on IFS + sh does not allow MAILCHECK to be unset (?) + sh does not allow traps on SIGALRM or SIGCHLD + bash allows multiple option arguments when invoked (e.g. -x -v); + sh allows only a single option argument (`sh -x -v' attempts + to open a file named `-v', and, on SunOS 4.1.4, dumps core. + On Solaris 2.4 and earlier versions, sh goes into an infinite + loop.) + sh exits a script if any builtin fails; bash exits only if one of + the POSIX.2 `special' builtins fails + +C2) How does bash differ from the Korn shell, version ksh88? + +Things bash has or uses that ksh88 does not: + long invocation options + [-+]O invocation option + -l invocation option + `!' reserved word + arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done + arithmetic in largest machine-supported size (intmax_t) + posix mode and posix conformance + command hashing + tilde expansion for assignment statements that look like $PATH + process substitution with named pipes if /dev/fd is not available + the ${!param} indirect parameter expansion operator + the ${!param*} prefix expansion operator + the ${param:offset[:length]} parameter substring operator + the ${param/pat[/string]} parameter pattern substitution operator + variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, + TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, + HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, + IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, + PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, + GROUPS, FUNCNAME, histchars, auto_resume + prompt expansion with backslash escapes and command substitution + redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- + more extensive and extensible editing and programmable completion + builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, + exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, + jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, + read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, + set -o braceexpand/-o histexpand/-o interactive-comments/ + -o notify/-o physical/-o posix/-o hashall/-o onecmd/ + -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, + typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, + disown, printf, complete, compgen + `!' csh-style history expansion + POSIX.2-style globbing character classes + POSIX.2-style globbing equivalence classes + POSIX.2-style globbing collating symbols + egrep-like extended pattern matching operators + case-insensitive pattern matching and globbing + `**' arithmetic operator to do exponentiation + redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr + arrays of unlimited size + TMOUT is default timeout for `read' and `select' + +Things ksh88 has or uses that bash does not: + tracked aliases (alias -t) + variables: ERRNO, FPATH, EDITOR, VISUAL + co-processes (|&, >&p, <&p) + weirdly-scoped functions + typeset +f to list all function names without definitions + text of command history kept in a file, not memory + builtins: alias -x, cd old new, fc -e -, newgrp, print, + read -p/-s/var?prompt, set -A/-o gmacs/ + -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, + typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence + using environment to pass attributes of exported variables + arithmetic evaluation done on arguments to some builtins + reads .profile from $PWD when invoked as login shell + +Implementation differences: + ksh runs last command of a pipeline in parent shell context + bash has brace expansion by default (ksh88 compile-time option) + bash has fixed startup file for all interactive shells; ksh reads $ENV + bash has exported functions + bash command search finds functions before builtins + bash waits for all commands in pipeline to exit before returning status + emacs-mode editing has some slightly different key bindings + +C3) Which new features in ksh-93 are not in bash, and which are? + +New things in ksh-93 not in bash-2.05b: + associative arrays + floating point arithmetic and variables + math library functions + ${!name[sub]} name of subscript for associative array + `.' is allowed in variable names to create a hierarchical namespace + more extensive compound assignment syntax + discipline functions + `sleep' and `getconf' builtins (bash has loadable versions) + typeset -n and `nameref' variables + KEYBD trap + variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, + .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT + backreferences in pattern matching (\N) + `&' operator in pattern lists for matching + print -f (bash uses printf) + `fc' has been renamed to `hist' + `.' can execute shell functions + exit statuses between 0 and 255 + set -o pipefail + `+=' variable assignment operator + FPATH and PATH mixing + getopts -a + -I invocation option + DEBUG trap now executed before each simple command, instead of after + printf %H, %P, %T, %Z modifiers, output base for %d + lexical scoping for local variables in `ksh' functions + no scoping for local variables in `POSIX' functions + +New things in ksh-93 present in bash-2.05b: + [n]<&word- and [n]>&word- redirections (combination dup and close) + for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command + ?:, ++, --, `expr1 , expr2' arithmetic operators + expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, + ${!param*} + compound array assignment + the `!' reserved word + loadable builtins -- but ksh uses `builtin' while bash uses `enable' + `command', `builtin', `disown' builtins + new $'...' and $"..." quoting + FIGNORE (but bash uses GLOBIGNORE), HISTCMD + set -o notify/-C + changes to kill builtin + read -A (bash uses read -a) + read -t/-d + trap -p + exec -c/-a + `.' restores the positional parameters when it completes + POSIX.2 `test' + umask -S + unalias -a + command and arithmetic substitution performed on PS1, PS4, and ENV + command name completion + ENV processed only for interactive shells + +Section D: Why does bash do some things differently than other Unix shells? + +D1) Why does bash run a different version of `command' than + `which command' says it will? + +On many systems, `which' is actually a csh script that assumes +you're running csh. In tcsh, `which' and its cousin `where' +are builtins. On other Unix systems, `which' is a perl script +that uses the PATH environment variable. + +The csh script version reads the csh startup files from your +home directory and uses those to determine which `command' will +be invoked. Since bash doesn't use any of those startup files, +there's a good chance that your bash environment differs from +your csh environment. The bash `type' builtin does everything +`which' does, and will report correct results for the running +shell. If you're really wedded to the name `which', try adding +the following function definition to your .bashrc: + + which() + { + builtin type "$@" + } + +If you're moving from tcsh and would like to bring `where' along +as well, use this function: + + where() + { + builtin type -a "$@" + } + +D2) Why doesn't bash treat brace expansions exactly like csh? + +The only difference between bash and csh brace expansion is that +bash requires a brace expression to contain at least one unquoted +comma if it is to be expanded. Any brace-surrounded word not +containing an unquoted comma is left unchanged by the brace +expansion code. This affords the greatest degree of sh +compatibility. + +Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. + +D3) Why doesn't bash have csh variable modifiers? + +Posix has specified a more powerful, albeit somewhat more cryptic, +mechanism cribbed from ksh, and bash implements it. + +${parameter%word} + Remove smallest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the suffix matched by the pattern deleted. + + x=file.c + echo ${x%.c}.o + -->file.o + +${parameter%%word} + + Remove largest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the suffix matched by the pattern deleted. + + x=posix/src/std + echo ${x%%/*} + -->posix + +${parameter#word} + Remove smallest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the prefix matched by the pattern deleted. + + x=$HOME/src/cmd + echo ${x#$HOME} + -->/src/cmd + +${parameter##word} + Remove largest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the prefix matched by the pattern deleted. + + x=/one/two/three + echo ${x##*/} + -->three + + +Given + a=/a/b/c/d + b=b.xxx + + csh bash result + --- ---- ------ + $a:h ${a%/*} /a/b/c + $a:t ${a##*/} d + $b:r ${b%.*} b + $b:e ${b##*.} xxx + + +D4) How can I make my csh aliases work when I convert to bash? + +Bash uses a different syntax to support aliases than csh does. +The details can be found in the documentation. We have provided +a shell script which does most of the work of conversion for you; +this script can be found in ./examples/misc/aliasconv.sh. Here is +how you use it: + +Start csh in the normal way for you. (e.g., `csh') + +Pipe the output of `alias' through `aliasconv.sh', saving the +results into `bash_aliases': + + alias | bash aliasconv.sh >bash_aliases + +Edit `bash_aliases', carefully reading through any created +functions. You will need to change the names of some csh specific +variables to the bash equivalents. The script converts $cwd to +$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt +to $PS1. You may also have to add quotes to avoid unwanted +expansion. + +For example, the csh alias: + + alias cd 'cd \!*; echo $cwd' + +is converted to the bash function: + + cd () { command cd "$@"; echo $PWD ; } + +The only thing that needs to be done is to quote $PWD: + + cd () { command cd "$@"; echo "$PWD" ; } + +Merge the edited file into your ~/.bashrc. + +There is an additional, more ambitious, script in +examples/misc/cshtobash that attempts to convert your entire csh +environment to its bash equivalent. This script can be run as +simply `cshtobash' to convert your normal interactive +environment, or as `cshtobash ~/.login' to convert your login +environment. + +D5) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? + +Use + command 2>&1 | command2 + +The key is to remember that piping is performed before redirection, so +file descriptor 1 points to the pipe when it is duplicated onto file +descriptor 2. + +D6) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +There are features in ksh-88 and ksh-93 that do not have direct bash +equivalents. Most, however, can be emulated with very little trouble. + +ksh-88 feature Bash equivalent +-------------- --------------- +compiled-in aliases set up aliases in .bashrc; some ksh aliases are + bash builtins (hash, history, type) +coprocesses named pipe pairs (one for read, one for write) +typeset +f declare -F +cd, print, whence function substitutes in examples/functions/kshenv +autoloaded functions examples/functions/autoload is the same as typeset -fu +read var?prompt read -p prompt var + +ksh-93 feature Bash equivalent +-------------- --------------- +sleep, getconf Bash has loadable versions in examples/loadables +${.sh.version} $BASH_VERSION +print -f printf +hist alias hist=fc +$HISTEDIT $FCEDIT + +Section E: How can I get bash to do certain things, and why does bash do + things the way it does? + +E1) Why is the bash builtin `test' slightly different from /bin/test? + +The specific example used here is [ ! x -o x ], which is false. + +Bash's builtin `test' implements the Posix.2 spec, which can be +summarized as follows (the wording is due to David Korn): + +Here is the set of rules for processing test arguments. + + 0 Args: False + 1 Arg: True iff argument is not null. + 2 Args: If first arg is !, True iff second argument is null. + If first argument is unary, then true if unary test is true + Otherwise error. + 3 Args: If second argument is a binary operator, do binary test of $1 $3 + If first argument is !, negate two argument test of $2 $3 + If first argument is `(' and third argument is `)', do the + one-argument test of the second argument. + Otherwise error. + 4 Args: If first argument is !, negate three argument test of $2 $3 $4. + Otherwise unspecified + 5 or more Args: unspecified. (Historical shells would use their + current algorithm). + +The operators -a and -o are considered binary operators for the purpose +of the 3 Arg case. + +As you can see, the test becomes (not (x or x)), which is false. + +E2) Why does bash sometimes say `Broken pipe'? + +If a sequence of commands appears in a pipeline, and one of the +reading commands finishes before the writer has finished, the +writer receives a SIGPIPE signal. Many other shells special-case +SIGPIPE as an exit status in the pipeline and do not report it. +For example, in: + + ps -aux | head + +`head' can finish before `ps' writes all of its output, and ps +will try to write on a pipe without a reader. In that case, bash +will print `Broken pipe' to stderr when ps is killed by a +SIGPIPE. + +You can build a version of bash that will not report SIGPIPE errors +by uncommenting the definition of DONT_REPORT_SIGPIPE in the file +config-top.h. + +E3) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? + +Readline, the line editing library that bash uses, does not know +that the terminal escape sequences do not take up space on the +screen. The redisplay code assumes, unless told otherwise, that +each character in the prompt is a `printable' character that +takes up one character position on the screen. + +You can use the bash prompt expansion facility (see the PROMPTING +section in the manual page) to tell readline that sequences of +characters in the prompt strings take up no screen space. + +Use the \[ escape to begin a sequence of non-printing characters, +and the \] escape to signal the end of such a sequence. + +E4) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? + +This has to do with the parent-child relationship between Unix +processes. It affects all commands run in pipelines, not just +simple calls to `read'. For example, piping a command's output +into a `while' loop that repeatedly calls `read' will result in +the same behavior. + +Each element of a pipeline runs in a separate process, a child of +the shell running the pipeline. A subprocess cannot affect its +parent's environment. When the `read' command sets the variable +to the input, that variable is set only in the subshell, not the +parent shell. When the subshell exits, the value of the variable +is lost. + +Many pipelines that end with `read variable' can be converted +into command substitutions, which will capture the output of +a specified command. The output can then be assigned to a +variable: + + grep ^gnu /usr/lib/news/active | wc -l | read ngroup + +can be converted into + + ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) + +This does not, unfortunately, work to split the text among +multiple variables, as read does when given multiple variable +arguments. If you need to do this, you can either use the +command substitution above to read the output into a variable +and chop up the variable using the bash pattern removal +expansion operators or use some variant of the following +approach. + +Say /usr/local/bin/ipaddr is the following shell script: + +#! /bin/sh +host `hostname` | awk '/address/ {print $NF}' + +Instead of using + + /usr/local/bin/ipaddr | read A B C D + +to break the local machine's IP address into separate octets, use + + OIFS="$IFS" + IFS=. + set -- $(/usr/local/bin/ipaddr) + IFS="$OIFS" + A="$1" B="$2" C="$3" D="$4" + +Beware, however, that this will change the shell's positional +parameters. If you need them, you should save them before doing +this. + +This is the general approach -- in most cases you will not need to +set $IFS to a different value. + +Some other user-supplied alternatives include: + +read A B C D << HERE + $(IFS=.; echo $(/usr/local/bin/ipaddr)) +HERE + +and, where process substitution is available, + +read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) + +E5) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? + +This is the behavior of echo on most Unix System V machines. + +The bash builtin `echo' is modeled after the 9th Edition +Research Unix version of `echo'. It does not interpret +backslash-escaped characters in its argument strings by default; +it requires the use of the -e option to enable the +interpretation. The System V echo provides no way to disable the +special characters; the bash echo has a -E option to disable +them. + +There is a configuration option that will make bash behave like +the System V echo and interpret things like `\t' by default. Run +configure with the --enable-xpg-echo-default option to turn this +on. Be aware that this will cause some of the tests run when you +type `make tests' to fail. + +There is a shell option, `xpg_echo', settable with `shopt', that will +change the behavior of echo at runtime. Enabling this option turns +on expansion of backslash-escape sequences. + +E6) Why doesn't a while or for loop get suspended when I type ^Z? + +This is a consequence of how job control works on Unix. The only +thing that can be suspended is the process group. This is a single +command or pipeline of commands that the shell forks and executes. + +When you run a while or for loop, the only thing that the shell forks +and executes are any commands in the while loop test and commands in +the loop bodies. These, therefore, are the only things that can be +suspended when you type ^Z. + +If you want to be able to stop the entire loop, you need to put it +within parentheses, which will force the loop into a subshell that +may be stopped (and subsequently restarted) as a single unit. + +E7) What about empty for loops in Makefiles? + +It's fairly common to see constructs like this in automatically-generated +Makefiles: + +SUBDIRS = @SUBDIRS@ + + ... + +subdirs-clean: + for d in ${SUBDIRS}; do \ + ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ + done + +When SUBDIRS is empty, this results in a command like this being passed to +bash: + + for d in ; do + ( cd $d && ${MAKE} ${MFLAGS} clean ) + done + +In versions of bash before bash-2.05a, this was a syntax error. If the +reserved word `in' was present, a word must follow it before the semicolon +or newline. The language in the manual page referring to the list of words +being empty referred to the list after it is expanded. These versions of +bash required that there be at least one word following the `in' when the +construct was parsed. + +The idiomatic Makefile solution is something like: + +SUBDIRS = @SUBDIRS@ + +subdirs-clean: + subdirs=$SUBDIRS ; for d in $$subdirs; do \ + ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ + done + +The latest drafts of the updated POSIX standard have changed this: the +word list is no longer required. Bash versions 2.05a and later accept +the new syntax. + +E8) Why does the arithmetic evaluation code complain about `08'? + +The bash arithmetic evaluation code (used for `let', $(()), (()), and in +other places), interprets a leading `0' in numeric constants as denoting +an octal number, and a leading `0x' as denoting hexadecimal. This is +in accordance with the POSIX.2 spec, section 2.9.2.1, which states that +arithmetic constants should be handled as signed long integers as defined +by the ANSI/ISO C standard. + +The POSIX.2 interpretation committee has confirmed this: + +http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html + +E9) Why does the pattern matching expression [A-Z]* match files beginning + with every letter except `z'? + +Bash-2.03, Bash-2.05 and later versions honor the current locale setting +when processing ranges within pattern matching bracket expressions ([A-Z]). +This is what POSIX.2 and SUSv3/XPG6 specify. + +The behavior of the matcher in bash-2.05 and later versions depends on the +current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will +result in the traditional behavior ([A-Z] matches all uppercase ASCII +characters). Many other locales, including the en_US locale (the default +on many US versions of Linux) collate the upper and lower case letters like +this: + + AaBb...Zz + +which means that [A-Z] matches every letter except `z'. Others collate like + + aAbBcC...zZ + +which means that [A-Z] matches every letter except `a'. + +The portable way to specify upper case letters is [:upper:] instead of +A-Z; lower case may be specified as [:lower:] instead of a-z. + +Look at the manual pages for setlocale(3), strcoll(3), and, if it is +present, locale(1). If you have locale(1), you can use it to find +your current locale information even if you do not have any of the +LC_ variables set. + +My advice is to put + + export LC_COLLATE=C + +into /etc/profile and inspect any shell scripts run from cron for +constructs like [A-Z]. This will prevent things like + + rm [A-Z]* + +from removing every file in the current directory except those beginning +with `z' and still allow individual users to change the collation order. +Users may put the above command into their own profiles as well, of course. + +E10) Why does `cd //' leave $PWD as `//'? + +POSIX.2, in its description of `cd', says that *three* or more leading +slashes may be replaced with a single slash when canonicalizing the +current working directory. + +This is, I presume, for historical compatibility. Certain versions of +Unix, and early network file systems, used paths of the form +//hostname/path to access `path' on server `hostname'. + +E11) If I resize my xterm while another program is running, why doesn't bash + notice the change? + +This is another issue that deals with job control. + +The kernel maintains a notion of a current terminal process group. Members +of this process group (processes whose process group ID is equal to the +current terminal process group ID) receive terminal-generated signals like +SIGWINCH. (For more details, see the JOB CONTROL section of the bash +man page.) + +If a terminal is resized, the kernel sends SIGWINCH to each member of +the terminal's current process group (the `foreground' process group). + +When bash is running with job control enabled, each pipeline (which may be +a single command) is run in its own process group, different from bash's +process group. This foreground process group receives the SIGWINCH; bash +does not. Bash has no way of knowing that the terminal has been resized. + +There is a `checkwinsize' option, settable with the `shopt' builtin, that +will cause bash to check the window size and adjust its idea of the +terminal's dimensions each time a process stops or exits and returns control +of the terminal to bash. Enable it with `shopt -s checkwinsize'. + +Section F: Things to watch out for on certain Unix versions + +F1) Why can't I use command line editing in my `cmdtool'? + +The problem is `cmdtool' and bash fighting over the input. When +scrolling is enabled in a cmdtool window, cmdtool puts the tty in +`raw mode' to permit command-line editing using the mouse for +applications that cannot do it themselves. As a result, bash and +cmdtool each try to read keyboard input immediately, with neither +getting enough of it to be useful. + +This mode also causes cmdtool to not implement many of the +terminal functions and control sequences appearing in the +`sun-cmd' termcap entry. For a more complete explanation, see +that file examples/suncmd.termcap in the bash distribution. + +`xterm' is a better choice, and gets along with bash much more +smoothly. + +If you must use cmdtool, you can use the termcap description in +examples/suncmd.termcap. Set the TERMCAP variable to the terminal +description contained in that file, i.e. + +TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' + +Then export TERMCAP and start a new cmdtool window from that shell. +The bash command-line editing should behave better in the new +cmdtool. If this works, you can put the assignment to TERMCAP +in your bashrc file. + +F2) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? + +This is the consequence of building bash on SunOS 5 and linking +with the libraries in /usr/ucblib, but using the definitions +and structures from files in /usr/include. + +The actual conflict is between the dirent structure in +/usr/include/dirent.h and the struct returned by the version of +`readdir' in libucb.a (a 4.3-BSD style `struct direct'). + +Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH +when configuring and building bash. This will ensure that you +use /usr/ccs/bin/cc or acc instead of /usr/ucb/cc and that you +link with libc before libucb. + +If you have installed the Sun C compiler, you may also need to +put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before +/usr/ucb. + +F3) Why does bash dump core after I interrupt username completion or + `~user' tilde expansion on a machine running NIS? + +This is a famous and long-standing bug in the SunOS YP (sorry, NIS) +client library, which is part of libc. + +The YP library code keeps static state -- a pointer into the data +returned from the server. When YP initializes itself (setpwent), +it looks at this pointer and calls free on it if it's non-null. +So far, so good. + +If one of the YP functions is interrupted during getpwent (the +exact function is interpretwithsave()), and returns NULL, the +pointer is freed without being reset to NULL, and the function +returns. The next time getpwent is called, it sees that this +pointer is non-null, calls free, and the bash free() blows up +because it's being asked to free freed memory. + +The traditional Unix mallocs allow memory to be freed multiple +times; that's probably why this has never been fixed. You can +run configure with the `--without-gnu-malloc' option to use +the C library malloc and avoid the problem. + +F4) I'm running SVR4.2. Why is the line erased every time I type `@'? + +The `@' character is the default `line kill' character in most +versions of System V, including SVR4.2. You can change this +character to whatever you want using `stty'. For example, to +change the line kill character to control-u, type + + stty kill ^U + +where the `^' and `U' can be two separate characters. + +F5) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? + +The actual command in question is something like + + < file ( command ) + +According to the grammar given in the POSIX.2 standard, this construct +is, in fact, a syntax error. Redirections may only precede `simple +commands'. A subshell construct such as the above is one of the shell's +`compound commands'. A redirection may only follow a compound command. + +This affects the mechanical transformation of commands that use `cat' +to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on +comp.unix.shell). While most commands of the form + + cat file | command + +can be converted to `< file command', shell control structures such as +loops and subshells require `command < file'. + +The file CWRU/sh-redir-hack in the bash-2.05a distribution is an +(unofficial) patch to parse.y that will modify the grammar to +support this construct. It will not apply with `patch'; you must +modify parse.y by hand. Note that if you apply this, you must +recompile with -DREDIRECTION_HACK. This introduces a large +number of reduce/reduce conflicts into the shell grammar. + +F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? + +The short answer is that Red Hat screwed up. + +The long answer is that they shipped an /etc/inputrc that only works +for emacs mode editing, and then screwed all the vi users by setting +INPUTRC to /etc/inputrc in /etc/profile. + +The short fix is to do one of the following: remove or rename +/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, +but make sure you export it if you do), remove the assignment to +INPUTRC from /etc/profile, add + + set keymap emacs + +to the beginning of /etc/inputrc, or bracket the key bindings in +/etc/inputrc with these lines + + $if mode=emacs + [...] + $endif + +F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on + HP/UX 11.x? + +HP/UX's support for long double is imperfect at best. + +GCC will support it without problems, but the HP C library functions +like strtold(3) and printf(3) don't actually work with long doubles. +HP implemented a `long_double' type as a 4-element array of 32-bit +ints, and that is what the library functions use. The ANSI C +`long double' type is a 128-bit floating point scalar. + +The easiest fix, until HP fixes things up, is to edit the generated +config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, +the compilation should complete successfully. + +Section G: How can I get bash to do certain common things? + +G1) How can I get bash to read and display eight-bit characters? + +This is a process requiring several steps. + +First, you must ensure that the `physical' data path is a full eight +bits. For xterms, for example, the `vt100' resources `eightBitInput' +and `eightBitOutput' should be set to `true'. + +Once you have set up an eight-bit path, you must tell the kernel and +tty driver to leave the eighth bit of characters alone when processing +keyboard input. Use `stty' to do this: + + stty cs8 -istrip -parenb + +For old BSD-style systems, you can use + + stty pass8 + +You may also need + + stty even odd + +Finally, you need to tell readline that you will be inputting and +displaying eight-bit characters. You use readline variables to do +this. These variables can be set in your .inputrc or using the bash +`bind' builtin. Here's an example using `bind': + + bash$ bind 'set convert-meta off' + bash$ bind 'set meta-flag on' + bash$ bind 'set output-meta on' + +The `set' commands between the single quotes may also be placed +in ~/.inputrc. + +G2) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? + +This is why the `command' and `builtin' builtins exist. The +`command' builtin executes the command supplied as its first +argument, skipping over any function defined with that name. The +`builtin' builtin executes the builtin command given as its first +argument directly. + +For example, to write a function to replace `cd' that writes the +hostname and current directory to an xterm title bar, use +something like the following: + + cd() + { + builtin cd "$@" && xtitle "$HOST: $PWD" + } + +This could also be written using `command' instead of `builtin'; +the version above is marginally more efficient. + +G3) How can I find the value of a shell variable whose name is the value + of another shell variable? + +Versions of Bash newer than Bash-2.0 support this directly. You can use + + ${!var} + +For example, the following sequence of commands will echo `z': + + var1=var2 + var2=z + echo ${!var1} + +For sh compatibility, use the `eval' builtin. The important +thing to remember is that `eval' expands the arguments you give +it again, so you need to quote the parts of the arguments that +you want `eval' to act on. + +For example, this expression prints the value of the last positional +parameter: + + eval echo \"\$\{$#\}\" + +The expansion of the quoted portions of this expression will be +deferred until `eval' runs, while the `$#' will be expanded +before `eval' is executed. In versions of bash later than bash-2.0, + + echo ${!#} + +does the same thing. + +This is not the same thing as ksh93 `nameref' variables, though the syntax +is similar. I may add namerefs in a future bash version. + +G4) How can I make the bash `time' reserved word print timing output that + looks like the output from my system's /usr/bin/time? + +The bash command timing code looks for a variable `TIMEFORMAT' and +uses its value as a format string to decide how to display the +timing statistics. + +The value of TIMEFORMAT is a string with `%' escapes expanded in a +fashion similar in spirit to printf(3). The manual page explains +the meanings of the escape sequences in the format string. + +If TIMEFORMAT is not set, bash acts as if the following assignment had +been performed: + + TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' + +The POSIX.2 default time format (used by `time -p command') is + + TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' + +The BSD /usr/bin/time format can be emulated with: + + TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' + +The System V /usr/bin/time format can be emulated with: + + TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' + +The ksh format can be emulated with: + + TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' + +G5) How do I get the current directory into my prompt? + +Bash provides a number of backslash-escape sequences which are expanded +when the prompt string (PS1 or PS2) is displayed. The full list is in +the manual page. + +The \w expansion gives the full pathname of the current directory, with +a tilde (`~') substituted for the current value of $HOME. The \W +expansion gives the basename of the current directory. To put the full +pathname of the current directory into the path without any tilde +subsitution, use $PWD. Here are some examples: + + PS1='\w$ ' # current directory with tilde + PS1='\W$ ' # basename of current directory + PS1='$PWD$ ' # full pathname of current directory + +The single quotes are important in the final example to prevent $PWD from +being expanded when the assignment to PS1 is performed. + +G6) How can I rename "*.foo" to "*.bar"? + +Use the pattern removal functionality described in D3. The following `for' +loop will do the trick: + + for f in *.foo; do + mv $f ${f%foo}bar + done + +G7) How can I translate a filename from uppercase to lowercase? + +The script examples/functions/lowercase, originally written by John DuBois, +will do the trick. The converse is left as an exercise. + +G8) How can I write a filename expansion (globbing) pattern that will match + all files in the current directory except "." and ".."? + +You must have set the `extglob' shell option using `shopt -s extglob' to use +this: + + echo .!(.|) * + +A solution that works without extended globbing is given in the Unix Shell +FAQ, posted periodically to comp.unix.shell. + +Section H: Where do I go from here? + +H1) How do I report bugs in bash, and where should I look for fixes and + advice? + +Use the `bashbug' script to report bugs. It is built and +installed at the same time as bash. It provides a standard +template for reporting a problem and automatically includes +information about your configuration and build environment. + +`bashbug' sends its reports to bug-bash@gnu.org, which +is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. + +Bug fixes, answers to questions, and announcements of new releases +are all posted to gnu.bash.bug. Discussions concerning bash features +and problems also take place there. + +To reach the bash maintainers directly, send mail to +bash-maintainers@gnu.org. + +H2) What kind of bash documentation is there? + +First, look in the doc directory in the bash distribution. It should +contain at least the following files: + +bash.1 an extensive, thorough Unix-style manual page +builtins.1 a manual page covering just bash builtin commands +bashref.texi a reference manual in GNU tex`info format +bashref.info an info version of the reference manual +FAQ this file +article.ms text of an article written for The Linux Journal +readline.3 a man page describing readline + +Postscript, HTML, and ASCII files created from the above source are +available in the documentation distribution. + +There is additional documentation available for anonymous FTP from host +ftp.cwru.edu in the `pub/bash' directory. + +Cameron Newham and Bill Rosenblatt have written a book on bash, published +by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn +Shell book. The title is ``Learning the Bash Shell'', and the ISBN number +is 1-56592-147-X. Look for it in fine bookstores near you. This book +covers bash-1.14, but has an appendix describing some of the new features +in bash-2.0. + +A second edition of this book is available, published in January, 1998. +The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores +or on the web. + +The GNU Bash Reference Manual has been published as a printed book by +Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers +bash-2.0 and is available from most online bookstores (see +http://www.network-theory.co.uk/bash/manual/ for details). The publisher +will donate $1 to the Free Software Foundation for each copy sold. + +H3) What's coming in future versions? + +These are features I hope to include in a future version of bash. + +a better bash debugger (a minimally-tested version is included with bash-2.05b) +associative arrays +co-processes, but with a new-style syntax that looks like function declaration + +H4) What's on the bash `wish list' for future versions? + +These are features that may or may not appear in a future version of bash. + +breaking some of the shell functionality into embeddable libraries +a module system like zsh's, using dynamic loading like builtins +better internationalization using GNU `gettext' +date-stamped command history +a bash programmer's guide with a chapter on creating loadable builtins +a better loadable interface to perl with access to the shell builtins and + variables (contributions gratefully accepted) +ksh93-like `nameref' variables +ksh93-like `+=' variable assignment operator +ksh93-like `xx.yy' variables (including some of the .sh.* variables) and + associated disipline functions +Some of the new ksh93 pattern matching operators, like backreferencing + +H5) When will the next release appear? + +The next version will appear sometime in 2002. Never make predictions. + + +This document is Copyright 1995-2003 by Chester Ramey. + +Permission is hereby granted, without written agreement and +without license or royalty fees, to use, copy, and distribute +this document for any purpose, provided that the above copyright +notice appears in all copies of this document and that the +contents of this document remain unaltered. diff --git a/doc/aosa-bash.pdf.old b/doc/aosa-bash.pdf.old new file mode 100644 index 0000000000000000000000000000000000000000..006a767769451694f5f25a9dfdb18282067d982b GIT binary patch literal 153472 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 Sk zX&oTJN`&YE``3n?p5gsKGLHZH<7{ij$QzCkhCf~t0OzkI*6{_H8Wu37imIN< z5qp%;JZgM*){a!|P*Si4^DOXxMoS~$o0UN&FiZRW3PUDd$7`V~u4-|-LKh`!M z0I)X`9MiGk$kle>31PLseohq4&#b2n`o8V2Nx@}{w#=f0u++*@Q1bEp- zN|hYPaNhlmQ@1&kuUTjtGFymz07*p<)*)$6Fs!gperg+GO`~y4cyKDyH*(y1h~eU6 zIX8hF^?>OVKBieiUIr?O6*p!T7=OVw4mY>AB4RXb$lV8KuV-G`@>o1(;VDS{zF8&L zW+>}S%^c(n@>8f*D)s7fY{zP^FhCG-r~w^7 z?L%Xbf?mDLN+bK+T^vor?OL`Thgdp#0S1oM+b!}F3zpwy#(OMX$lENso!DRsYm4qT zm-AI3Md)3yABkbHglCk{ABn`)9b8bH>~8&NZ=E|q_bSyJEr0BRFED4H7|K!3SfS$y(uds3ULnT1Ayf%FVMi9xwD$|?+_NxqdUlcwb zN;hA=Y3YUI4dL`QDP!T#UYhnh%nlMDza%MmU_G5-UbQ4YDU|h*TUKd~^Uexx0fCWW zUho|S3@EnPpUMh(DUIGWh{!M7;5KN_ z-sP#Z?gii?U@KpEG(ym>Ys?qJ|M2T!i3jl+w=XMv2FNjF*`Z^e%Q4W}fY!Y^g7U~b zP=3zgdBN!tT9x`ICUOp3keaX_uJwWSof0a@OWI9GqAb)MoaS$j6|@S8PKTs}K-KMAD0bs;blP zRCpf^CC5^@VuOml}cv2$vBFwShGlKZBub zkq326pK`S3OE!acy}U=kM3~$=)h%oXQu!!50X?#yFD7AQHit}_KBc|AKo502RNOx) z1I$E;pYSS#>GjPf%O^uzQIlP5Rdg6>U4MkY5@30ac>a{(0@7_eTMdmAgvd!!Y60$} z66gzyne%X$%l^oMccTD*iF-EnsAARPUX@nZ6VgyN#gfG6lfrE(K=D(4G={$EAugr$=W5UL&6 zJ()R$eZ2dJo`$SNeWDnHK>6|@ifkwVy?C{73;@ym=LcX_(N}emnNjAH8SUBH$eF}2 z@dX9^*?g6_v{&!^1&uD;HD34;Y3={|I1o}7^la=oBXvw&Q`ZA4cw>R~Tqb7Vx%h+qR8w+qP}nwr$(CZQHi3d(z46$(i)}1@CAj^`ufMf(@3t z9e+Ps9#1wmyIW9+cZV^DJ>WN3nl$ES7Bm=PM&%CtW9g1rmy$39RuE)(k^P7H#bhT& zGL;m8dZ&;Dld8u2g3sl~rXz?U3zj~;Dy!IfDx;1uTgLq82$`C_(yW%kt(;d~Q~-s+Idru3C`^ zqXWIlB6Oi+DazA3 z06GGS%@Ka8;y^(m=a)k|q??k757{$j#Dl#lL$z91{^sjY9|m8iZ@Z4js0xE#h-Md* zI1Ar2AR!k@w;K?~&U7!XF=nmT%%CTSE;F%~m$sj%Y1nk5f9-*Zxh>7Gpdh-Zt;4q} zq8Lb%Zoqc=qYFk1lm1{}D`96Xi%g^&@5Ika1)YzzH=DY5OX8nLt$CpaDC`M|(ByJL^!6gMdJQgj;M-XJDH>HU8EurgI>kTL+9Z1#MD%nb3QXT?{UUJlwnjX)t8v zBOdB>9XPlEtLP@*oURR6wd8 zXJR6%ri#pPf)mLlOEXk;{s~NJ-gdK#NtFmxOJZDm>dir~a$=$Es73=Kd5=+=D^btD zR0MUTnv>}2-!6m=+ntr{^B;fH*6ecryLN5jyE@gS=0}D|`C5lH$8;N`Qv4N$e)oZ( zuW$VhhY4$bgRmFbTU#U#T_NNTrh%B^>CCxJRUPwQXS)?O-%_LBNw99XDTZv3phMYq z>=!7n$_9!%&&qktuOfjj(B(xQt0Ubo3h@~`KKB>7y$8@ONXxA}OXNxt!+)Ry0mZ0% zB6fUE*O&~nhOkf*EH0Fh^o_hqh#ZE7LYO%Y4CLW`k{IoOAkwxKPf%6V?GP293zLzq zq2-=$!|lQi@4z2bD(7ZBF42l$^-Z89PYA%9h*BC@75AKG?euR>csp7ikt>MoU$ESM z%WKC#%cS2BUD>Iob^H9l0kp#r+L!pFADYJ~I-CVoG zih>ntM@dV+Roa|?qMkbpcR6DTp5{%MaMvM8!a~}Wsz@v3kqU}Sx=YGHsM23Wlud0P zK4ch|a;m^V&?{&_aPYliPCa4yN7MmRK>x8WfxhlxJ8eHOu_=JcGhWlY<1IRK8h7jR zs-GDtNt~s)B!;cLok)dI){TES*$8_Fsj)n~AGo(HapsXB7}6{YpftqwM1*;mnL63i zP)*cUP;cOk1+iy8+qCA6avaiU8Sf*b6h9%d1O2Awp+Jn>vjRNx2-q{V*c6G&~69bL0BMr*Xy*3e6}t5ona{fW>M; z(LOp**R^-!c`Ke;Ju|mg)pt~wf|?V#Po($n=%l22FnAu1;Q1zcyi4tn-5iS;K41kD zoo+S_kzrW^QLqHlfliOFfzOElrng9@w1Qnl zgK9sk^R;l)mZDJS{S!VGx{x(l(kOMgkonL~<(1JlB@-RXj6(UaWNz%sqdP6`BPy=B z3?n{W5*8kvgM!fdhf4day;M2G3TyGZ@gX%&)w@_3$l_vHN}kC(R5UfM>p9#9W0akD z@QXJ!m5;X%kU(0;)^dRcO|1k&x7PTa`XyF{RJ6(mN4l^&F}h-qh1ef_g3a7t4lK)g zib?=h2*z@ZZkjXv`zVR z%)I>A{uEO#tb~~ZUtv_C7~gfQie=h_qf7(Xmt>4l=QFw;|GNLTe7p zrD_q0yGzqP+xa1OMiyXknait1Cs~GO;9HdcTM~;6?h-?7|3bA7x!a)$YLA6wDyUE{ zhGqrx*uo&aqir|Sv>kZIE`aIhF!MhPWzPo(8}rf7EX-^AWXu+K6ze0s?C1lae&jSWn~)NUe_ZyVU-}Up$hk;m9IxF`B$Wghb$78k z+{H!2DO>hhIeAI^`xMKa#xkEnn0Q*DEbdJ-?*}32@o3wPX}0}V<(w@&93nqa!JMOu zCWh576BtLf|AM`auFHq&i7rwdRBB=^yv^|+gf+)4knD)^g4iKbrqqa-VR6tY$9#$U>~>w24%X3;X*OEj^2Uh`Zrubi8@^&4O5*$f%J)4 zJ=~pcyL22yb3Jqs=jiF_=EZ`2!r70cKcF%?w|d9!ZwTlTPOej5*I5Y$N#opSegDyCs~>QPdceNmAb`|xbvSR4LRfB2;o1s z(c#Ubv{R;gG|AU*SGiq5@mTcdfr4)lwD<|ChOx7s@Gc$NL}V3+6n?*8Yi)9<3o{iJt4-2FEN z&(J!3plam%`+DTIS2NWZ%&vuY=84Y9*S;g6Yw9w9z45lQd3JhbuimxDQ+KuKubq#X zzMFYhrg3aH6Ii9m>=TuuGR;(c)9)@ixnTQfh6A6?Oarc3JqC(p)NW6(%_TbAtT?TCP?tX500A zmLIzb(`*#hDZfFZlRdli&|F>}b1|yZt*`M>bK`utHoa7TeUwgHRaU7>V`WfcE3tZm zw-zfcpH3iXKv(wu#gUUle*ZbH#?W`+{(|}H2@%;DlTz8Baipob80y^gjF~PjG>WE1 zc+^-)#cJq_Gg2{Y#S|&VI3ap5hx~N3kY9C0X_EjdEW1eIb8#7*;H0u-FCTI4rIw>s%b=Do&WgsktC9LDvg6&Ft z`v}jbpfOso8eWEad<0spV_5&MM0ZFnmAfHwW~;jVyRtG9=2`mRN3$zlDP_+^*N%Ze zj+dT7cJ>$Oo1sA?mbi+K1&4dgqBR{g z3qE}9#E^^iVRbk@9bv3dB%9_RQ4d)_??vcrMp|a-y8f> zA7wN3UN(F`;GtWP8OLW-#X#6zB7;B8#)!<9+L7R!#=$7lKTkx+95a+Rg!bn&WiPne z^U1(wz8aE8djTstC&vv2l!yMh@^#r4pbDpR%!>_5#4m>KT$0}h9gq_JbYsMSTK2q% ztrqepV+VOXu@6vlxz#(wL<8_<;x-S0>v3lBe?bF<6pJUWKW1o^p)jDj`Gc$R1aA?3 z0Sg9#j*edh?;HD5xfh(VJ^_B2_d~b`&g5Fr$ z;?)8Jy=^sM|04YP{J}Mv(}0_Ljo^h~?Lr;aB*vTMb~=mTyMsaKG$OWa<|4B6p!g#G zk+pc(Q{JcDc1INnT%VI&=Yv+kA&G@xwVY0!jGs@^4=4ga4I9&>A5P8y=@QFfA0^42 z1f$CRs0y5Ef~BGwBh0>`-BDH{rMsaLAOT+GG(z1c-YVP=78oT4z3zNh4;P5)HDo(X zsEtqDKT}RduY~6uFkp$zm zd&V9i{Uvj6UATjcWey4D8|5c(^=H9aQ*Ce=`=Ojt#y>=8E7}fOmkHOomSar{>xZ#3 znL>`jwDSQV%EJd!96;1+Ld5=}0;IqF9KeM3D2zhgzqD zP4n6(>U8@Gd5fh$Zw>*IHALKv%kN_%b74`8T4mbP0=gJsKGpHIAUg6~RPXBR{(a+| z85<`BM4qanB4$o8$dQmrxADuR(SLD_CEngGlV|)qQO-`F#$8MXesuGn8dN>o^yH%f&i8F?Iu?XGt?ZI^sH(AV|wJMzq>$! z(lzttD!L#Gx3Fd(j@^o?ERt|dNb~5TqB)?vJG}F{Wl5=&H*F$>Pk|X2P9^{;3$fER zHDEbWQ6AqKLh=KS429HJ(#Hx%>L*BO^{A;i*UVBGX~}vexwUJZXpW2& zAzh)FCjph5vDcFPs4+&sHO3JBm`3ZDkwYJ!x|rn%dcs~Zy$Ds8?<1;va~#SC;8 z3VJd+Q_6%$?&Ad&mIwx|lQcc1BH<@vX-+P{MoYW{CUeoMl^^iK>!QzmPKv027Z}F6 z|Js(~RWO8);6$yvKpuQb-RZ7kg1&yY^zyT87h%UsK6|?SJRx_KLsQudq>(M5``lz3 zm*GWYkx)MvmHJ8q?yi?nGV`GJZMta7dGs%ST!JIrEVYarr9LN)*x6KUOGpxmrO&$#V>ZWCty}?kitabS8 zkM}!zrDT(8OACn?G3C!82ax&oxs6qm-X*hi<*cXI`783S4i?3+rv{SpaFMg zv8HTL91g;SKNPc$EHu3IfnkY(s)$`|^~s@kVj!Lt9Pfg0cx;Gl@RNnC5SDC8%# zk`VH9sZsj`7RA-U@u)TubxZ+<*Wg=riN4)}xh0$f4nWyg0fWzovC3Awa38vH^rRqV zw^^}pL!+n6C>B(6nu^`EB*-r2RAwG2+>#Al9zO~r-Ss{6)q*UH-sVLxDpSHEQ*~^N zU$IbJ+h0&bngVKs6xTs|s(je|&W+7d-Tv|a!j{B4eK;Zci;@rEfoyp)QwJ;n0&Sn) zoSQzQKGtmH`l+2MK#o#Fv2adpRopw2kM^SYC+J!v4ClB+)vjm6p7PdbuP&f}%!=%Hq| z%ckk*!VQN&G=ZXm0Vp6vP-*Hhtiwih9Shg1xPrPUu64+h^9zyyKIq_~7T_-{w*)}$ z8b3@2H`>(OafiQh^nP0l&wE@4+{UdwtU+AljDx9ygtFWw8zHq8ks4lg2qEq9l)f*?2hnO!CdIZA1gaFcVVUYLM<0eaO zigxW3V092=$YE|9H)*FNbU{+2Ty}A&?=j#C?Ke+@_hLJs3C5_cm|O{42KA7?I~VhX zA~k;xEBSopQ$9+FUi9ECZHURby&c@yUDtRCztFj`S}nb~=O=x@!~eW<(J-&nwPsoq zWv#3|5`Ls5BvME#q%{$Omc!`QwK_(zF;FfXZyUxrV5<&BiZEzmAH>mn93GTCqFuJg zOh9wg0289b;sZ%zx?oHRfb$MTsc)fs5G}?xk7%cfEVUA}<-pl1_{)?%X7C>TcIW|4 z^N}2HhG&kcZE%U|`&fuaL@V%|EeI!G0xrczfgIiya8k`7cy8)0xDwqnUKRDUO>k~k z;Nid=^<-VPi!TbiTX7S;L8mmyMIn6%q@ym*Ngiz}S;V)pC+foyYC!g;M;~|E{8;Oo z78v{U6FR_cGM&ZYNzlhRG0{Nik*IUIV-2*rvKmQEoB};>ALhvBUlgGp387x1pIvG6+eQhOGlpa)%?tUu+@N(&F;K_?q0PXeT92WAUE#Ujc^2tlr6aAIj0!Egz z9CZIiVtBheoOq{FGOModfbkYt)9dF`;xTg;-G@)+JuxUm74Ro>o>&Df<`z{*{??uA z_#6fYe@)A`xNOe5_CC|CC$G{l93P(ExsrhPg$uiTrF~r<(Zolp?*ig+d*ZB;D%D=1 ztRT{gp2*KS8bd#uimBAXAAP2pWY9!*Z|Q;JuZPdlPbDntS%C;tOk>A0Ge?KzDix%wkaS7XX)`4{5~K!wneC?ogzkNc`D1?T1bNMzPb0tx>NQwnI(o4l+$vgOSh*lSM$OWBqiXse}|UTh7K^KL4qCzv~(2 zT-6AV|1sqfC|v4%q5pa))EnUNdcJ`9p$sw=%D^@ic&Ig+?;8xK(;nsqixn-t7QDJZ8JPchW9Wz*{C1Jr7cv2V-*LCkr*?nE%clmu zPfyr3Q{9TTN}48YW$)_i+v}cA-bU0VjyiqMU}ZRaIJ@5-%tWG19|u3!EgpYEao@`` z_bhJ2)rx0ee?=!tdpj0SKfKYaC#4fvie08oe~6|B>@5nSIcYJw%A?0B1?+ES?0*Rx z+oxOHYFFJBnb&1DI>(|1m)BkVJ$`RTsv7P(=hygcDXV`Te{$m!k*yUfx+|pfeS5&H zXRWmq#`!xG+eQ@*`#Ja?Wz^}lSh)aGc6Z7ODD};wB~x5h^iK?YB*Cj)6VN%<#?1IZv`r_AZRGsAkbmD@TU2Sd`krmiX~A6v!Kfn1ZUp*U5!sz&Q_VWp07Sa&-`q@OAF0SEs$d;LK-F@$8)?9Dy za87XCw(&%gbpX5)C~{WvJZs0bC?j7_t(Dy%HDm{E=-NY692o3o^&Fu)F z&7ioyO~A#BGV+l<_?l*2H44sPszKjrXr-wRms;QY;vL_+2Q)Z0IuI~MZr!(ETt5nJBVGg z0sHrVqftN}wKtM@ESRt@I__*zX}Uqdb3S9Kw=_Kjyw0gEiL;t`r^0^HqqtiS2b+BL z9#jl3ZMg}Wt=T10&t(N!u}d6YP!8NICA{i>9P)^dwT4-Xwr6JKHn_S4k<$j6s-DeW{p@_WsR=vI%zevmJeGmQVQdP8=6#pwFH_g@qSoe zSu(>W_zb>{m%5uv6+Q2AV6EW0tLKtDHPY{p9@(b{Y3-}96SiDAp(Yo|wy(S&VuoXE z8)myHtQv7d){1KO)PmtGDJe^tVPOvMi!H>rSSaOP&tHPRe%p!6RH$Epg{8dSn8+1{ zlR9o=27LD81&k)Ei{xAjK7XLXeD`94V~ID545`VHLWOOONrnMm>yj5xQD>@KzMH2x!s3*`&cMBR#^Vhh2ALC+JgEe zS)-(axKZAKy{|tV_-_cNp}BB-jl^B(WfMUH2<=ggt_oPskhF%|nW3n!eQn1_2R7+f z<7fFPVdz6bwed&c?PVWrgeMm12QcJ3Nc(La15#uT^;cGXrHX?^JL#GL- zI22Jdwp@NRgj|J7b0TSt@+NA3fN&a?RyORou?Up}g2B)kS#yJ7BvMoJ{|PthbG!=YD{>^N}(K+OV)ih7bv+)4{PzP5l>$0c*`&X0NPH}KHsRWzrr0jrl8xqkXE{0D{E+5u{^ zKK#MGs}vZ1si_iV5xIQ&rk5e&##W3k>@dsbC#1CVdi#eE!b40^gceCLr2>(SL(X4e zgiZSZpwV+m;;5uX6b;vd#yawUtAI;@a}4bz?rYWo?@qxb@cE43Pbx=zKFg2J>m`1e z)KBhs;|`c;}6i2^;VUFtc7f=!t9;3GUS&Yqdje&X9xZ?J4`wt%?*+eGCsN(hOELVB6jFJ8qKYq|2*7w)=2bL$ zw3P$$a4EF9jcZ*5lRQ;(awfI$))iv1nB;$+%U2Q!dLLux(vXBtg@=GZWDe8#4R(rt zSyYJ&W<|&L7=!rX{PU$TDy38cnEmp8mj)DDMURX2UPGmN{T&yLOH|3Z&T$2Wk?HsJ z&K-bu;kBdL8d#Pil-wK8ECB}9O2N^8rL@FAr96fVa&9bPq(CiRlENYJsN)z`dA#a@ z>d!ZMUjzp#0bj=f^vG}yL8^kPI2FsOR+J7ogP~|Cp1G2%gC@ zY)nVAmxcZip^b0sBaw!^SboRS-^(%do1kBR&2T`hFaoinTrlP?5P=MQUEl|He!nRK zv6MuJ_At#O;(*?uO+{C*4GK%x7fW?TL48^2jYJ(u>nrz6Ixe6ut*Zo+2O;FvIXQCv z@KdICF>nOGP~d7J-X`|G29nEO9KVuE^aPB{3xZo5P{r}XSNPY@cM}Isk?1;rMu#&E zARZc^e1pOx2@Z;X5l;mMMj4i`5Z_-=D6$ACi%u#jP7dzkCFzo2bwpwu#f+$zYYQek zUSl;Uf-EUt7Oze*EyE!YsRa2?y+q-Bo1Ec~c+O=XtdlgxtaS)g(6QZk+Lz#i z3tu>qNX49^dOy!DLkt7#j0p6nu7YiRRC9)y&~o=LWd7O)&A>qPrWolRH+2aOEL{o+ zall3v*edo&R%9yZbSRlbD(X*npjYSsSc<+$4kB8);Qh?OoHv@)*}1#8;1V^Z1wlja zmGC;y;x)xE zQiY5?1XBNIxK-g?{gDPL5uX!zK0^wAY%ih8A5oE!W;mO^%b=q#0dE+%^9p0Jww&3wJNB?@#@XB&T|O*K~3w_xPaG zu2+lfd0252zJ`gQpX3B{??H3~(D|VWX(5w}awF6=u(G$Cw0YS!PwB`ZDdsX6Hu->P zJOL5Jrv~D`ukEEiRzFRnzlaXO*rK8oQ$}8B8N9@;praIwDD;qFOo$w1xk0G@ zzo#5Hryln$nE`$bxsv`1sMiZ?dQ}#cn&*h_>l((P-sRl81ehY)8p{%ja*3y@(UtU+AnNigi@x{R~| z{euaT+R0^hX8=-%4LC@7R-1yu2=XH*pX2V=-LO`LgH}}AE_e;NP#7m_%KpfbM_T%c zISToX7XIykX@FUu%((rM63NL#N9_s@>k_=mk!U25TNzC18$RG<-+*Snsq&S*NBQR~ zu?OE@h!Ot#>GeChkNRU?aY_Jo3s{50KKEa11nLqdw#XE8(;H8jCgqg05_45*6Vd!# zTyjb>kl}cicL%9tx+?jJAa#!u2>OPlwP)#V3RfRwlVm>rn>cBmkZX-8FhVFvyAbZz z3stLBnf1!}B(`A0yvPlc{fei}HFJLg+O|;0vs8=E>3iti4}D?6&eHzZfxGrnXj-Yq z2$jgI^lCMq_sc+1oFUUZK5HlV0xWp!N)TQq-@~+TgAik89!) zGdhetYC1`>RM)F77o*2XiHnsoIG1ZTi|S}z5J>vne z1uFQ?=bdK;xW3VGRTJ)6B#P+pVcx zB}l=bEIS#tMC_g*c|pn*>I0!JsM*Hn1H*ULVazn2?pR#Vr#8He{F1`X$CS`&^mv7Y zzp8fi1(I3#h-zDw_vzo^SE&b?dtZq|-{56xhjPR!gV(Pbf7;TSb|jIIt7en;va5z5cBxQ&V2n4L= z^mkG!-jHW;vq2Gd<+?;F%9=?$Bx>4$(CqQNJfq7)n;^Eu&yul1jxL0`_W_&m8wu5 z(d*z&O=Iyq%iis)vtgt{gqB95n?EfUjkEg{w-Kd+GJ4lU}%*yMr)o{u?fLLbzQCZGCdH8lM{c zvP`Zw8%Jwg$DE?m#X@b?;o@iPPDimgi?dSuUIBnv4qb2xyG}WwNg#1k^O+#kHEhC& zUgiXISY?Te|?fs*IH=o8tS1Fuzu2)?~qYN(VPnF z$rbfd{^(q`Hj(cgd=opD@?}o*ygIg-0TiO-X2B36j-2n2lg@-tR?S&ofp1bord)Uj zBvbp4l{*nC4QZ~ZwW6!6q4=nE;y7ez755Z?opy01ZD~iO`7{Vvm~?Y(dri@KE$?E0 zzVptAHc#)1T*2AOgsVEv$a-aj)wRps$$H;Kpg(V!T0;WS*!S&=LhP2qvkthF&ThE} zR&K-IUBpMFKh9vN-(4pl0-e+PSP8L=Vqrq!vn#rVH-iq(>lx)Y=QOx5q)xwZJ)~bH zCA3xl(gWJ!l&h7RDioeiW}rGlDnBK{WlVdg`0^RGyd-tBxV|oh2guR90va-4AG8B8 z7XAK;+HTD!T0%F_?E1qfo@>7V0zqfJj$;HiGXZ|6u2RC+x$fbR-`u{dZ&i`#-vHY(&viTTgI1!Y=9_% zpt&Ja0(r(;O=(tBqe<_k<0pYXAioc@t*UM^c7kcuJL<~jUbxG$^3W{|n?xi1o{f6? zK8M^^>2AlW^6Hq>$Wmz0N}4_l`TwMK61n@uhGQPqPQxis>{*a+!&z0t_xiy418M3A9*Sk ztsT1hJ_k@v8pW6Vc7H)jP0W@Wm&q+O29~#AVZOaBbQITGS@gO+oxVQ1PGn9ktr_Sv zc2W4`7FpQa^txB!%=ol6i6m@NGwgm}ch>6cbZK$FWviyYF+HcN==(w&M4@DMyMGQ} z)bwbh3jH%!lbn1bSt@)0ebT}tqKX~8QysQ$UE7UqN6UOI@jkjP*uNV%ab0&hGd2@^ zi78LlrMF(g`(iUs44EWz1mwIzDStD(>aI#*O z@x)Bwa|Jo3f${C{4lr5(0Dnpa$(9hImRhNu zTX&$7@-kA@*cv`YwiTi~n2^(fBR|JZ@DuVAK}x}Mz~tZTGefcQTXCDh#{w5Cis@XM zs*&qjJ^H2vu!_SdH$%NEx|#OJe_SQ?m8m*!O*pewBdDK5HInzqcm%F_?}#2Lt?#R>me$u zkwxuBY2m77EJ(q#240t>8}Cpcq^2%IcvxtRZOnS`fVQF{?&S2 zzwX3NYxSJu@3mye3J!-{jHo^4#;J$E@Z@taj3ag?<4RB^9=Wm-O)twF1$S!>sC5bZ-!jEJXMVO{B%`}nJ zRgU+LOj9MKQlF1`TVK)&;`|^r$MVL28Yu$9!6Bx%+<7v*#?S#@c1~Ls&t;L@ICmn} zZH;EdKh9Hl@kz3PLqKF2O(e>@Fv(f|mb`N_kSzM@n9Z9IJhNeF$u!>&bBX01Sl zLn}PL-*VxhHvF5G5{X0dI!zTA(I!LM%2U3HFd-nW&pqh9^G)#In;u1;9qqNe_2(T3 zvfW~AjVJqEm5Y|t2cN0kDtA3@KsuvgWC6Ovm4ZRpFh~d8(0;0yf`p}{n%hru8IkWQAqiW?-#9qZkQfYr;iS4g`j++4xgzYcRJX6P4(6Xsv2 z*!NEH2*#Ke5*$ij0k^l>LgrZ99qj%+l{42me6|J6Nn{Ov7s~RlL<}sL&7L=&pR`Cf zi-G+L+(xn$@}ib*uDm3#2^1oFaVj?-voGY?%$9SAWv<`JQ1Jrqh1yZJv3Csilh>mI z^gTEzLO20F;=vt@E!csRxsZ5)!G+7G)vnaPX73ixo$37^A<(a)dg$fYJH3d2du-sy zH#TLHsvOLjLr39u{mINA_H;w5BN9Kn#7KZoJebunOv)kYQx4pgZArH<{|FgrCii4l~(ztPSAW*v)W&RG-4H&bxxVu)OPz&9yl zO~PBBy2Qn$i<3(40XALJ?UPEiLZ~7sV;tnrt(qXIdqCVWPVzF0g5N`f@YC?zQXe0- zmI&Lol04yAg<%2eYdVZJTRGl-0Ip8#;q|Q@p(Q4$wB|rCK5`ymkDfyB4jUETalD-J zR-quhKSw63WupU`O0yo?_9S4>CoJxQzpvd+uc;uiUzrtKPz}88&9w!-0@#FGr*RE! zKC$8gbm6GnTZy@()Lq5-f*5X`u~shV3TMTn8->Iwh69s8!+l{V(6ce59|R8qg#Ork ziu`843(f@xrb3Mt$bo3r3Z;HwVH=IOJhIBtl4*cESa6V$I&lwBaQ?;&fm%=^#p>28 z$y5W%CPvc<$_~jjnQp!l?*b|l6I_^iS&5_FB#>bz2gNHTv~kTmnV0|`Bz1WpPm_0K z&!zZWvIh!Yo~XnZK9wIVFj~3gvb4k#j;Z3v)@q?^Y$-Bw;M&KOi`2<`bQ>uOH1KNVNwA$Gwt$8%_E<(- zEVRK3r5L@kiVSN{U%{DJ-C@sA6P1+TN%!RRXSqt1iyMjro{&HAS$&F}>=l0Kfd@ET*T8Gq^z`_X)C(+-n!d8hvds`Vzx$4R`8^xT#JP1_<5N2Z;6m%B zvYZG84V-N@6P!vu(T{4nDxr*#;FJbvsxn?QA9qagbS3-4nnN^nRg9MinJfrev*ReZ z8~@aR;WEESfPX#0zAOcc-^~=H&I7U$ROcW(*^$JGutVE#I}|X&la?IxxjZ%Wzo7qT3Mo{ zC!7f|hg!7NkS>m^4De8Z&bc?tz4RvjE5x!JjE6~6+jFf)OLOrz(@HZJ#fBXwtjQ|{ zEaxc+i#ye5wQGrNx?JVry)4EJiSy~g{X>H!UhqX(A>L!KP}7*x5jH%Ww&ajr3Wj+Y z(bU1C(=I5_Cwepp1M!$k-zLb!ciEqZ&rzEQDIM(@pI(@5BePT@7kwdT*G?)^A=Nub zkqHS{O(gW8LKV~MF+j1(t;A5KvpA!H43*TXx8`_B2Spk3XfdPvw0c+&yP{ONzk*4l zu{PRqjb!XZ`(BX7 z19Z#?VP)*iCr;$g z0rwReS{`UJW@-jOGKvde;NRut>l;5tK8BG;X69WQsS2|~fBF)rB-N8<3(q!lw{x6t zLe!b^-b@B$9SF0+_Bg5pF~8$$Z8kK}^az6VLOT_#8XzO`;Wpe2tz@*hCtxEmiR1$} zaU6L=1WSBx1xko-!}Q~}{RA1Q&VsV(a;fCyBnh~Nc}wzwoHWc7u~J$YX8;RDI+bbP zNq5An^|O58Y_m%4KegQba!EDxkwdUX?(eKzNtkeE8c*9rEm!aF`u@hG#p>$Xv#%+I z6)x0Au-s`@#_3}Z%4oa6_svPP>w_(OoevDjOISk)2;jdXI+`j#Ewv4xrdT3Wv!^b* z-QC}#nX9;DL6xNW0#ChMIWhPN@O}~O=ui_-sPB0hEmAEi$?-^W0>Ea6f_py{2V98i zO1joRj%(QzRkc`c#!tCy;`Om7>|jj@R;}rBBbVV49WLQ zmCsr;@$R!<^7iJ3i4Dr^(gfu&AW0e3`)hRSk4xRV&(7wYONRm3A6E1gM=(!|-x?w8 zL9ER5c#pDl;`3_p)D@PVR>Ja?^Hkksj-V#SVEC!!F5IDbkI%t=(qpQ2ro3-p=B26% zMkj1uxl*T!f_baSZc+%K)6wn9+$Qqj*6{u#Al#a&8 zAr_*bz5M+M=hCR0pPNU;UN*SGb9YImCs0#8-Mpj1_Mvl#{XnsT$?G#H-^r&zgr^Z8@Ffp?eYEmf+`lrYAZviFD<`K8TDu>Fb@=}n zdxs`rpf%~XY}>YN+qP}nwr##;+qP}nwyVB#2iJxJ1lz-bdv!w0Tdj=q_Tr=y$l~pU zq3JN<54zW`xd2(WBEBag7}rGJnE;(03F?NtjHd0ra`rZSEHO3dR7bU4eR4=&uHCq% z)bxI6@ASci1PK=M_jm>n{M^9{K4$Z{Mo!T)Rffx5ojp0vm8=T$C*TCI zH`YFW`tc&%7v>5AKGICN_@HZAvWo(qcd!By*O?2)@6z!TSAfVUgC`{*;{PL?LIQt3 z<79okR(${^t;RjX5c9Re);A3oqa~4#!nvrl_0M=0jg8!2`lyQCr`6lj^M&?*_V<%O zf4jfxBcg`g_%G1J_CKO)7B(h^{|VXuTXfC-e-vFyCvS}+_TJU)4}=>^MH}E@08B`_ zU8g9=p?J3)s)%w1kTi>c08s-yTTPt={|V9kc3s?Fcm_=EP%Ih-db-N<_xc6kt9z2I zP>ucl8hW>X{=h5M-j-Iyt55#tNFJHQs!$Jq&&rm`wp!88RGO4gO&4>J_HXI?bY$I+ z^mvQ8T%^`lqC+yLLF%GSS4-rq=y)Ab(}8dVF~0|81*#V4xVeW^dQ) z`*mujd;HO7_ZMVC3vnT3W@;L^eghXrH)&F+IY4{$Poe#Ov#wi>)F!=UE14fBZZ*Od8YZH)^Y>{9A_ z)NQa0OOEwWfF&^}tj5)LgyU|jNS|&b+-_ag4s9*|?ni209DO_!DgQRx@N)D3b(#{^ zS*v-*jTUyd1S!yCVC$fxa%8BttKDpmXI?S{p5D0gYy zW4rJ@MR2nJPh@EL_jKJxn_so?8-{OP#m^%IStgLlQM)BW{+G#69y|r&Ue(5_$kvcojUB%CtefsE65aN9PV9kN6 z7kK7`d(l7A$7<9-RBcPuP`0#xL~^m9nYeOBONm=bZ42o}kmZNvGgHZC3^?Ou79Pcj z%a*K}Wt+|Y$^($?6pNoG%r4u((L!Ovf;SW`GOqK~u4bGUDv^f#tIT}< zf-f`U)pqX>oCl{hK(^F<%f*+Sf3)NYV@@FI98@b>xmlehlQ|odV^ZY;Wa3e9isjt2 zg}`zEdQi~a|1!JdC0Xek1RXK94?Dx9$#J)sRY_?!JB3m*!v)bjWA7ggL%Ndl()1|x z-|E|q8{AZNGQ3=D*~c$SUlenmu2byNGMV|@mzh|$=qTNX9bkDKp-dvd_Q32#)_ysv za+qK{R|my;AAidNu43$Ltg41gqu1pUrbK*m67YF$HoHe+HD<{k9PQ*3E}XyQstX4k z&~(5ud~&uBi|6?%Z!abhj?J!YmBo{)Do9cM($27Vi5pWi^91vzTU=XpE|{gx0>m6@^r2#5-M* zIzX=f|{?D%c;*7&!qk%zAiH(Td^wd8H0)$AkRP zVcnwYtdjYQDDVfd@Vlf=QE7ma*4Pm|wmFztz*Jj3TKL}%{RzfA;mu;n@7WmyGDYBW zrWDtYi6IHkF_W7v!bdP`chFC&P|v>#M0duX3|{_jjjd*yRY@p!xX(Cr1jD9S!bG8; zx4k!Ag}D@R*yN7y(PArb$-px~Fi3$7)j9v5Z%}z#ep`SZ?G_J?V9W)e4ir*l#C_I$ zHIRMMw3-7Gy6Ah`yAJ(KNGG)fy_y}V=wsfDxFoDb4Y9~=-$?j&!>@(2>a=c0y9aTQeyG)RQ?`^cbf_y_5h2F-XfTY)VHVfUv4cWVt=W!xNVP zPNnQI#_^D?!6{K;x*zrA&ZaOsH&d*_KSp=(H{Kq7AX^g>u60)9Tua(6XFXfhF+(~*GQ`95Lm#35sP1B(Zq*LRb`oUM-slS z^@`SeqN0~tGQ!(xwM%<3oWa<=uFIAAnW5LwnF5zmFd1*;87r*i<1P!LKGKw97Zq%$ z-cGZ_!AQ#hv3g1o@-3X$LJVbao5)J+mi7mA@F#+!5DTN*_uvuyT;BrF zA}(>5dloM-#D}jh+-_$#MI=!}sgS8;3nwM3r$brEyqJ`vr+`UudK?|lrk4r_d(P7Ai%X$GmqWSH*Qme$tcfW|L18Xy9x%!fs zh=5d6{8P?F4ifVRqtM~b;5OtspJ@L^NHuj$nh&H_)^PqcE1|CL29^LR{wd4_ z)b}vG`Hl~oM=tZ9l~hR;ZlOY-_Ir@)M!q30_b2B$+WFl1WWLnbO;L!Vuj{d0+`iEi z4~40xc{Va9`NJ%R9Ug4rZogOWq6i&q?znmg@p&UJ0|_=oDi-9HA3F&x=(EnZHhQYs zup2vKYUWt0>z+IuUd9oc8jcb%USD`ns7ogJH=@oM5wN$H>qBZ6V?m6%YELMd5I5C3 zNmA-u76uF{s)SBTb!kAFqsPM_mj_Cf{#Z=-Gp${3U2a_)1mtN$-=pA(hJLivL2Vhm zKb1MSx27XPn*#{#Q;l)y(BR;NL#AFy$s0U>-CbQNp{KLd?gkh<#D=-q%v^x+u92M+ zPTS0fa~SQD1rmZO51q#sHhj-AYr9V}17T5s5S|E)1eumv`Xw)-ry=peiEeRwhb_X= z2tjMdW512`Kr45cBIDEi#hnvog$dBWY4FKxRpS5oo)P|OWb&IF@lwi zZpXkfQpnHcER312))L1B)x&8g>B~$D1CM0E-TSWad}5@7q@Qj;YW>5P-o((LP*W&2 z&=$DLtuGOEm@g_;EBHoUbTs;Qiv$LTtMzFD)I|J^=1Yo=z1JNNG+r*K{H}W=f!z7% z8_Ove2zr(jk9U6tAkm=-#`cEUi>ib?T@+bv3{JC9h~q(dnv_thJo6{B!EDuX;c{&b zb}g{g#kBzG&9}*R!z&}5!U~mUAXT+XuYa zKcWZ{+L9tW;M))#@b9$u&aBdkuSgyC-*T!Z4PtxV8? zqF?QRC=!^0v2k(C3U)D7Iv6Ep8*qt`%(&aO$6*~34|f?Mt)&Nf#E{+!=#%mVUDQ+W z5b9@P`?-vN9^EJZrb>bp2H zF~OV4I3C54xi>>ERRI}b4l|zioB;E1?9qH!bjsnC*_F1_SG)TyoUKnVE*=SevoFfB zTuF5@6K2y@0)XaPtYLDJnW2(e@{rqK({KvHW(#fla4&~?!_1|UdUQ2+ct~nSNO?&` z6aDe$>mL0_^`@!616zL3Bh#ykhI?H{+|$Eg-U8_nk>HX0~3_G5%cU9bRr96EDTO^_^7$# zT5yeF{f{%h9UHv?C7~!(DOMcyK~~n(``Vp(B~Ns-%jvlXSZx|$qIsky+#sKh7=G$9 zR$-}{*dE6{wJAsC{a(G`K+7N6Rc8dFu0-ZOSw{5OUHs7iJp`;AJE)2fG*& z6V1h^(FOCB=7-w8C$xyx+Jsw;fWi}lyX+maK*8R$i}j#^1decKk`H)Jvc0>mjDznN z1V74b1Lhf<^Coru?x9NE1=#JFFqh~OoHk_jd*&6H#2mkC4!Ga~@7JTl0)&ZB0z$sf zPeeH7Z~Y*rBR+Tf?WFln7*H~fvT~vSgf@xYQ+}?X&X>WJ{(tHaJeUsEH*8E8)P`1< zS9@il7TtlQR1Nce&`_$T)r-_3%wqJ6Aug4o_>l{Q@g)CBQ*jh6jZF|5`i)9sx@R+7075y<5%Da%k z_`9$$YRISWyQN}pXK>pe5GKV<#(xzt_Ww0PGqW@OZ^-`NMU3PB`rr7rm{aduokg9i z0JoXJGIV^8qE2lItfrQ7Qv>+aLBES}so}psHDFmMpRFIr-uF8${TG3`1VU%JST7S* zQ&Zm$Q?-XR*+l9d%KN#$bzJ-3j~=D$vX9fX|9@jN_OAK=ZH$<=*QF|S*6LCX(hp7@ zp4Mg}kY-MA=Gd*Cp0@Bmtl5Xwy0HyYxY*z0!{q(%;Y#c$_;^jSz{#6%T{orBs?oeg3$5J)j?S6m! z?tIt(s`+NQ!b#<|8L+^=}H2DW+UC+Gn z3u&thDCYir?{wk&t#h3fm=7%}x&dcd<}7jKa`WeN>kg2p4lM<-p4fSpMg1G^G==3>r&L>fi)T;_{U_6k!}UHd`Z_=R z6X)N0hD&!oPrqZ=kyA2&;&riZ&F3=I&o6(|fg5I*agp3S|Cvw6{ZeLkK6Z;1T}c3N z>GEo6tsq}AQ~Hz_>RNdIRDo-*agAfz;wKgP{jnYvIj-OsFx4)zOQ*m&)8a;zy;dN+ z2q$yH;XbsAvN2Xe*<=S6%uqVH+ft3TZ3^q8%60_C8r!t7$YTq~=gp3>Tk-`f7Xfv(ytPyxzmQEz$_TIiwh(B2mtyE#_E{UxRF$ujpdRKLPe z%C_Omw2m3(zpbT^02FE9WCBmc{d%N~vPa+caI`$@%+=+$aak!=QrSJf#zpI@mu}=( z;Kzj}d(@UUtCBfDhq-=4sm{=TnxWT(o*4QK;vd*>U8gEF@S~uhl3T;d~sNf*J&4HB$umBh7&MWWBCq}9A!<@ zveB>wUZXc-%Z?jgU!v&2Z!aqg;S}pl+Db8Op=iBf-n?PwuG#4ew~8^X%T@Vr!q$?l zq~Zxms^W+@uGT8mcWV~>cLg8R4#T7zhE{6@6!%x&gG$0xBN#2$3TCpuSmo8>BE07h zOw~g&8eah*{K~b}KAp{PLT<=WJBX|5TF4;{f^$EElW-SvJnu#z5{R77ZZ&yXL&msoEgt_`{Fu$B5p}DPE$YwL9<3J zGgW4-$8l{yZe5om|KP*fI>S zgCVMPdeU3c+7KE*`mh%QL?Y+4H%BYl(c&@u+@&XmtXdP*^suF>-R%6wBQNe-Iv}tt zO@Jy9H76Nn4%TDYz&$Ld$=ne7#vt>@u?iL6ISfXYdoRA?*%6$DKIoR!t{qB1GP}Q3 zKxSoJ3zVIDbOw3}_7Rda6J3>qC3ijg^v0hV_eEdPrHnn-G@P}k_I9xfJIjP&r1OZyWSr?=i`PC17NSvsJ-Tg^gK zkzzoAhuOm8*LF%^kyex#6GP>X#fe97g~xxV{~O)uyG@7ib-V`%E0X`gL|3YF-%x4j zjEl4Nku;l183iGs&QAx(w~-Bd0&`KYVtrv!r}VuGAO1(UubZi@ya62z!ZA|`iD|a1 zP`}&QwBB@yZUSt~5;CqpiV?FM@7)BTq&Q?=fvdFv12LWR2DJF5sQqCO8`&q3y*Na; z*6daKRPkC`Zz*7|YGnn>|83@M&v(So>!-lEwp#D4CwA$_<$U(I)say@7o^<|cBmS} z_vxce22iM>QSmCz_t2OAXq&dqKGowQD|mR_tmY&>$amhP-KEb)UFBobm8)Oum2`u|aMmwk0!N6c=;_)tkw!HmoAUn1{0(m&%{lg-Eon zyyS8Dk!`h*_(<-_MW*{a+z$m0L6?&@glOwCbtM6R)bR(fYc*3*p!S985qNW;ER?vX zdgsntWWnv;L}L(CXRtOZAjQ8oEre8i#d;+Y5H zKWph#y8}(;@6ESA0E_P8fnX)|z?5K0wAiE2UdUE;Pu=7J(CP9X?;=(;Qv7PJ(3F4= zDN&aZqqrpX{-`A0dZrb={xtYpekuUAW}W~MY&OOmVvGxh8OgJH{y+&8N>v!ebL-=Z zawk(wXufNLeD+5mZT|A8Gtq!V;_?z>CqYsFVH^psO3wc6Bzv&Y9V3^?O6eBuP-j?R zvf*-jd@xG}mm}mm>628iRO6_uA6O3UO`VIE%f64X_?t}eZ=gle%O(sDjTWT)DYjZ~ zcHL1@4AuJNC>!-vq9Os66Nyz^a}3UOiDuMyX7ieE(1Od983EB0@``}URst+ky^Ne> zZ`!wFTJLqKVX&>?Tv?$^sNek#)LCtkxXsT4%msyJpyW+jlszOV-Y16R(KiF{pQEPq z3-(rnluHkmDFRX7>F8x(cC>s2hf<5saf^|b_>@}1sa3MI&WGZHtrs9Uz#*RQTJThb zPW+MwLIZgNaJj~^Bndtvf;(CM!^8r`R2#Jbd^vpMxSrx?Mw#JGFuz|1=Rf%jHab$v zZ?**WDV%rRaj2iu7)DdEYPx~YE>$xT^6mA?441(`7onJ%S4o^rw;!f`#eWE?Vx3+i ze*oeeyc)B7dK5vt;04lbO>Tj5d`mc`{clq9U_xnq?(8 zncTE_-JZEO-0Ou)Bo9r(p>le)#mVZDVrX2gd58*Cj(u6!pv_eufc;b?TL8K8=r9-% z7zN;Nv7WD|S+W~KXQc?)|7@7d8&5(SRwAtWh2(ZRba@6QPR(bHs}gWUhA!i_5+rRo z4Y7sr$2x}l7=@89kfHr0CKk6;w%2zXm%{P3@W=(@kzZE{@PS zxxZISSY{q?e*6`KR#;|GrI}Q7uc}b2g~?LMtOxkt$o+9R=k?&w?|u^qtijylGC1)N z2lo`{Jm5X<1JITvr!}0$*Ck+}6nN+~dfrOtqK5>x#|1l=zd7q8EpPe99&tm82PoME zEE3|1hvpZu{@kN2t|N_Id-6#QtaU$NQHf5K^62z!zcU5s(Z?%ZXqPIBv*Xi-IqDN; z>8+X|&(fKis+YfnB?tr5jJXCtOQC4uW$WzLpJ}q$XB8w=T6yw2HIid!ry?N#S?>Uh zVh}G34T;id_wOltLGJSbSxa1JLG(y>d{eb9t%X5a)V@p(agrxOOdjyGqA=RE50{LK z1C`D?s}>=dQ`{WaXOWfe(Qpe}8Gw#Hgl)hZ)V=CL4cBPJk+}{`Qx#X6@^t%4p2E8X z$C2*=)~*gH3E#%{y50jVH_EOqglhMx8vz1aRE*Sr3~D(4o7xlUgfZmlg5Hkp$&N~- z-7>nkQNV2MdGCV6%j4tyo(%W!z-oOk6V@lqnnhkDVR>TWZWHggN*NXA=F@esmzvlY zt*8e#vGA};aj#Tz$I>bl=oijwQ=QOc&j__&%fFS^|J_;*s4F%8!)n4u|D zSfIgVDFpm&r$m5aOu!M1k_eKt|Glb3=s=l{incJ<740sEmPrGzi^<`%WQsR<_SAYT zu!a{`4h$j|V!e?l$k;H=mGpQq5gwErMo0+>h8 z+$;h2vutQ5fhJ}Vm=L!Rxx{?uE)mJ8oLOcGlI@fYDy-wv1nh~RJ3WR6O~x~Z66W@C zn4Xhr|MTo(@Ub_CVeNj%Ym+6Ie=m|lChei-0b_|$?6#W2JR!-y{4iRI1FgO7dqOY4 zdqA&EI)`g`PI9F|*GCMno$0Dyg$yQbDfiPn#{1NSLqs&+@oQXf+vu_eHrfEugsXRo z#$=umgH$XGj#{$Ai`ckLs9}H4El+DD z$xp5hBd0s0BWmr?89$;hmYFJY&50Co>x&k4%VejQ-?%rl?d|WOT^w6ZbbizSFarXn z>dPA)2q%)hdgkZ}*Fre?H=p*){dncL1W|T&i9lW0$8_JCfoH#0yb*Hbi709GLAYeI4agyiHb&^pyYL ziGa`Kn@n={#5ZLtqy_5D!13v+y*b~Pm{>*FXoE3R)uUYneCpLXJomA!<=A<#x)fW0BA71sn<$fb;fGQ!j?gZk$_HJWZk;9B)EBwjUR=Dy7n zH5>wmU@9Db5+R)MGqAwsUnF9~LH%MjnN{JT#1%3+mCq+ah-y8RV`__>T)0XppYgf- z4-*Lg!?m`i*xuOL`i&tkUmF(v79PTLuMH@;I#O9$9+$ z8dObS5z24nN;sqw=Ri9Fz9drZY^TEv^cR0_+qGuawe?&x3XQ1SE$lPf?(%zEpTGe< z6S^`vh4kI*GAfS16aZ*z{~8%`-lY5i$8@hbi^Rt<;ybIZfbx)IH$I~dOE%Xb5y~A< z20mGwYl$GX>2$hZqDoInfog4qv$JgOLnwj=fahAW39`ya*p+*~mk!1yNAGei(l-aA~OtX-CoUYH)TlMwEZI@!DEKhXr|#5UvU z6^>%mp2EafAMHVVV-krZaI5;QblvW%f#o6SR6%83c1yYmCon%$FBhOR1aiPEEw^h( zUXS*iw_F53z1%|QH^6b2!IXE`F$z+UvtaycsdWj`dth7T^M=OY;qt;bX25%382;%Y z{+R&5cBIvM;a5(+pS+-P9?y>c;D$)CI{4;KDM7IOf+=4a83s?8((d@lSM(4XKT1>V zz7Q|d5C9uMUQrQ#F~oxw1Fy9|7YI&@C>rqek_MZhK-(xp<&)A1mdz7%eVm`I72!%P%%$*gx7sWr`vpr}lZ3%YJuZ-&%E z!Vboe8T>;Nt(a~g;P<MVq|+t3Lq64&ImlW=a1e zr(t2`Wc;6ygZaN$5(mrwjU{O&ABj2n-RTdA&o96h(cx5)TeHAz9i$q$dkM$Y{h zyBLR)Py{VczuUf%d%S^j&s73-iDOB_3j?^CoP3z7z0Ortvbd=p{CygGw||ZCV>NkY z-TC!4_0nM@tF^G(xk|*R(&yT%e{t_&C~v;DuydIDzxli!T}DuMu4KEro4wr5ynQ$4 z9$4<;8K$?oyyM&E|Lx+b?ePs-XxDW%R@t7b#ormC`7u)~x0vp1s2=HTsJOj&w13SF zrn`3dLDbN8)l%)Khi6y1h}Q#GcL2&z)U-KErgacecxX-??$&d>+N&O;$FJ z)Vl%tWt6@*yOmOQd~y_@f6REU$DSERcTq)-N%P~49VN?1l6)h*-5I(cmRd(O z>|KYqyy3x<#9Y{6D7zD+sc{4k^Wnk|Jv_or_AhP9I5-TaD*NXh1oQ@#)l%Lrr9VjY zJstFCEnV>BCJ?r_h$qo)m~%iRZF1@7c<=MW!IUGH26%Q+DH4Ml-n8+`hD3-il@-(Q{PqgaHz1R-HA} zR_pdu3M;qPK)fcpRb;Zx{b0&9u;t~^eHM!PuH9VFPIgn4zH$A-fG_(ASTrw5cu6}< zNq2d~>cBPVH#F$YK-0~qZ~UnB$XkVTWx;SjexPNPKKW|jp|Tv}y* z*8qQw1s^zS+{Iq`LO*=nZ|*Nc_C7r`>?5xT^m!vrfJ$qN_xYO+TEDJ4%QV$iRm?S< zq?mpdc=3qw+Cj}e0E(-l3OmSv&djlIT?{w_SMz@EMfKEILe@C=@#H#=0;cWbdwYjhTpKxvkT*0XUjTnJI}W%o*TxAn zz?x6$H(}stxM4^h#NN!kQS3D<8=WJg+dSJb^l( z%$ln2T0^AEhYxfI-K@%+(Kv0lx4)tK2l{F|JK*UKFDm*42%Zb} zv+hSuvT__ZjGxBmBai@2z36w5|J+1Rcka{Gb~*za9j4uo^O%lhPX_gL#G~DnS(~Q4-m-)NAg^d7MI{CBv(BC;+P}(9;jfc6IIlM z@RJjpQJcQ>lEmA$ws(wmZ2MgNO)*+Q4*`yZ6Ic|92Ht4Qp#|XBf4iD&2z#*=1hWa? zvRu@WVPs|#lvc)va1O?LJGXHu!%YRVA*AiIH8)pTb{_j3YZcx~CwQT;z=tDRj5gj@ z7*X(#%&@3sU0@I`MP%?5+R!_$gk(s7X}KX^UifoXrbcoX`l1w746P_`v);2U?_Ubc z=53iK$ws})drwH5S)kD+h>?e6Bo>6h$(~{=Iq8fp2PxIEG72yPCjy4 zj&~$Rz%F`#5+%_FmFl@mKe|{WmJ~gkFwf$x*Jiv(0>PAII4h)G9_kUmerYHMS0)i1 z@mSH(wKrf+_eSb_I*;a;R_j@3=W~l@=xDlH6K}x`ozDJZiKyyRDIG3}OY}tfKe%9J zfqb^;=33`cB1F--AH&4EZK527EhMw2L3T=E(hH%GGT1W{AXWOgr5r=OSrH=!cf|`7 zOj?0z6In!HY8Zg`$s!a=3Y6ZcS~KW}gY&g7YT`4(kF_tO*~UiY1}l?~kJ=1ZVZBtu7cD(7FJl3{Fxpjr7v!y!&g6 zds~=G7#%FvyW2EHG#h%10q5&{LMw}9_mKia&_|_(*f3y#CEC69!27$M6!YvSm%4m_ z+$te9dJtV?1rQyoKtUd?iqtT~69k#~gO)hA#L=cEo#E-u_w1lwdQL`oBv-m)9zgbI zF1+X%k+!4#r=UdtviGbppVA)(RTHQ@P^Eh@M<}jNbS@a;fjTL@(WiQ+6>AZ|bcQH+ z;^yHnzt9|)I=-?Qr2H7!^Ot}6kDR%=Dg+`&5_6huekh*qlDqXVlb;a@NN+~{FiPDd z_z+W#;V=ok#wS<6Lt@${aY@WnE1%eF_u5Lwc8a-AZIIskA-l2c&ii zEfWr-7*+DJRIY`|3TK1DMbH5>Jn`y5#TJa?aP# zaOV3pt9_o@Mnmjj(=3TN8Uw=XaXLk7Lgq3` z>`+fZun2?HydMN;uU)QMjdjCN5S~1)%PEI_h(_%3J-cM~l9I5$A zM&Yyc9)PML5@u+T4)}h$p;}E#9V7fGz5K#)^t6SDa$p{cbygcfaxgxF@^^!1qfzzc zW4tAZ$$xt8XI-m@IkyRyL+`r{^TPYde33v(Uu^X(`0>Pmyp-BKeB>nPP{IrOM_F}X zn*0vXDUd8|L(fi%p(cZ1#H^@gSXR`Yr^1`zwz`RDW7FF?Eex5~jkUy7C71J6DM7eQ z)R6p0alGoiYG_ZyLg1oeAXbKrZoInsZZ-Jl>!fQxxoFudp2p27N zv>b=R`>W6-0QMm&cpim_1zoYRnclY}APZ#1y%A*Q|{Pl{0+OzC44#`Ky8VB+;mO_eoVYhb7viJ%f3wHzG698$06Fj+KEN7n_ zX1b}tXczftZtaiKY7BS^MiEAh=QwYcrmBMyF0X6iQL_#Vx%gnJN8;@CAc+oNsNqZq ze_P0fxaHfUOI8|x{Kdpsbr#ou%N=`4Y*?mduz<{L&6FO$z=T@}1=%qhFc85!y$9{N4kYTC3`2eW;kD-~5$A8di9RUgFc*>$#jEAE}MF91lW z8YHC2m)1w`Kj)kBlxUt*EQ=A2o1n$UTtnY@LafR+Mv%I6d*_D|1CyQSHpiND@+j$) zEj?xKXC7CyX`~o)>D^OIGWmn;mV9yExuKRH^rF@GhO-F3$9V2M3&9Kwc3C%EcYFs& zA@0hqNPG6PX=te=^IUP7tzH-{qb>{X(uW|=l z{ATkf+PR1e1et~DxLht8WyMHx(@(xwXh>~Y)|t%i&hzwJE707scN1{;X&jKlE!lhj za(Z8b+F2{^+^+%z z+g3n(X)$eb8d+j7je_)&Rs_8>?l1*DBv}P(FA5xW5If#Ux1p5ao=)pKZOh77w;AKq zVka5i7hVtzST42L9v@go527!5X1xgLd`G5p!{IMsZ?^1Z!e2%73aG$ZwkI*~s)b>^ zAmx((((Bn8GpFnIAq)m9vJPe=^VOsQb2<{xRpCLXZ>Veb3Q~C2{h&{Z>D$a%_x zssVv)Wa4bBRJ~G4B(2n{B{n*1wVgz`4CQYn+@)Va#zb2qP%>7Tw`zf{v*w){l4ven zEl9JPJ~9PaS7=IZ(-FKpvd2f)H(|1!LPeWeB-?4?J1OJJi%FwLj%stUkJvtlCZAFu z`he3k$XWW%xgeSa7f9V_Jt{F8Gg?0EF&qOCc!cFeEPMTVxY*>cvDJn69?oq_%Bf%t zFRg8{P0~ZgfA_s+$ws|vomSJm?mlgkeQ+5;R%(gonu_so z*L)_H5=XacJSU^z0`lim?Zy|S$=!?3&;rihT~@dnY<#}R(ci#AS%9vd#X2p2Hyo!9 z)D!|DGsUX%L$MwiH?3p@0Qw}8P3oS1Y>`zmt-Jyt>lerbgHQ@j^{(l}$S$J8a|3aW zkG9xDmE$UM*iT?Pt2v6^@*kZFr$oy&nzZ7Gx#aXHS&js0KXCfXTB$q>TDcT$0Sw8( zT~_f*9nANT897AkV)cl}S)tOy%TDJx`)w8S{tjrr@|(9E_KS4_&0%hwYDAmA)9|Rm z$T4ft-;Zm)nIPj$uFtLY*)VC$!wJr@=&(h$NyiHB|9~eSeCX3o!P2*U4Q#-6b8y&? z(L{MQ+CuQTYSZqecY0}ji+`hKssjnk5viSu*ysqucpAJsEX$87^r5=*hX&@5SrM3D zbu}$oN!S5+fU|j|rfObI0kg4Y#6^8;s~i+C0STrMg(4c-=banaRl%GecRXP{dGIDrVv^(P}(wux*V!a*CO=++kf?v z!$^M@C*8JH{H;9t;1@U8&lP4!A21xnqKZz(eiFh{(tZfdw zpp2E)LQ}}yGO{HfBZF1O`)eK0t&i|t^Tb$4*Ta_5os0)DCfle<*{?~*fUI#i2bAhc zQ_qi$KE#h+k<+g@`!AiHJPjIm2r-DL5sR7~zR)b-A)^(5pZVF`wq?=M6S<%_^);oP zsmwxUu!=bPypBKswNW~LD-NjsVbPkAoIZN_SOLIHQay>~*$ecV&&_mYdmfvpLL3&%!=qN}t5T@<8ViiH?>kd>yQ`VK{hQt$Wlh;Xb@2mCK6kyR7l z_g25jlE7d7A#3p;I{Mhgco^24={^}faVbA~Icv*G5J*F!gPuapnDZh&Qt^gv%ukHM zR5y1@#$Wh5xa!I!WZo}4Y#2TBe?c^k|FNyGaIpOEGKPcmzaSbX!~adeBJI2_mel*C z{*2foXrxdM9OhdhzrQl&sD>rS}3|e+NHoYS{KCZ)*_vsN?l{EzD2!;p}cxy zP0L~G{o?Y{wt}bLT-AnOH+^}umH%PQJh0ZhF+^u;`M|%)_t&#g#W+;3x`4VeytEt-B{&SJ*)_xe?@?dIu+4+9g_xt$NmCbGqzNe~; z{s+oClKsX%q@gdUtnKrCu@eq&eaAa}ossiFX_u0h-5IF1#Hd+jxEBBA_*cHwIx@7m z$X1K-`E*L-o1zIl5ozN-_Ft z$E|>0t%Ux=5*z=uQ_nBIi4i3~q5*fp$_A3Lf-+}qz=p7b7XF_jVjVRc{QD--|BPG@ z4e~C*;e7UWrzRUrP7m`y>T7dH%Xq5w;Q zKYi(8c+mAJ+Jw&5odZ9gcd5Nb$ZrC`FLRfO4F^r= z*+6U2y;RNV^G+*etSu%;e{ZaNqW!}GDH#F4htc|<^A7R`fz6HX1N63a~h zsn(jHkhNp1G+<=>9SA*!>_hvl_k-vQ>Pz_Qo5X`r7?vESvU0&li}EsKBywg%1PMeL-8FGQYm&VSSn`@|iB_T%`8 zg++z758o_7!=Px0-R%0wD`fHKGeR^AgBt>+AGRt?`l8&(?1DZG{Nm%6f-h|ZmzDy+ za&aJWX2Ctg%SN`irhXF{tLX&R(-|Xxf-EEV5Or{6k&L)kIA6Z>qX8*8e68U_XRI}V zcw!tnI&o{?N4JB*PoOl0K#jkUa1!vzEuw;8am@lM!A`(sa}Az7_4ary<)WO^*VaWz|S6jhp`>}32GPXe6T+Ml&!!qXRL?c`IPw= zdGhuFxi0VFQY|`d7N#~U$<(%CV-V*nV7Mwq0^iW@IU)`A&rj^I{Ir|6nMX*U9{0L@ z(1Aj(UM9gcTAltrAN3&}x`B7QMsAA4iH{61u{H#vCfR_H>a#8Z)}YK# z9ed+o&gncupOzx}&s@O++>03Q1MR5jx-(50{{Fq3?Zsd^R-B=nQmEQz^>+z zO@be~9J9y}>WhmhUxl~NI9s4FU7HAk6>D&UgteoB zj4ZGxo;e}y!idibmAjpIULQ9H21CtCK`}t^_Z!bE`!n)Cbq8@_?5NO4AEsSIW*M7( zL?U_L8d#O&lWst=J~4{S@bobh9-e86%SIW4IevaYtpu{L1#Ev#b5{HMaN3T*ZpDk= z1VI-@h?@rf5eVCG9F&4K>1-(xrM0&Z+-0fC>~ngo@3fnPgxv-Ww%H2^*JjG0N*$6Z zB(ARkK>T!vA(%-NF=kx1dC?6Q?u(Tva;8nAK>0U{gdf$*pR*M!X5Rn?HjBMY4Y3v4 zkTmuU6-6O(z{U*SlPLNRICh|Ry<_2~gF?}MGR(?$Fr~oBsHm!rW!%m5jX;(iMBWxG3Nqk_Uv{xxGBx8PI_Fo4; zs8ADJa#Z-I;EFOv48d^E`vidcN?FIAJ%42y+H9fmnm3j2&;yI*C#g7In&DxGWMcSk z#Vfa(=F$0Jo^la1vgyKvw>s2;z~EA@Wbo&QDgHYU+9;_dtBml&DiK&v z`qJ$K957RU@r*64tCa<;CRKn`G%&FpQ+#C}rgQ9_LU(@H)n<_8?nfam|6l_<(O(i^ zn16da?ghi<5^kcI7gS_`cmbq@f*G1H2xWVE3G|imFUwOc zU8I#dyG5WBnwC=&2n%%Fg;^4T!sANHl<#0T(nC1egS~dN9PseoP3}sZj|$?@LJQ01 zL>GHVR7yE_W#;D?xAp9;0% zg~{Yj(TiZD>k{mfv>HwJ!+J?8xN)|x*pK%8yU7wFnbs&xEhi(yi*$oKh9#bmeE=3l zDKrs@47fKujhI>7)`GZYP|o!<5)TAFwO!LREv958h5YHmyRGd=wv96_{wXew{O(9& zK0z*h21#}vZJUW^&}8b01v=J3#nV0;OfD6@BS;q^jd^!m4BSV8*ZDEDjR=x~VIRqM zRbH#}B#JgvCZB)izyqgo)oDU5I~N>urq6C^)(rWVF?h@qrJOT^5&i%7)@%%n2L>Ocu&jE^Fj z;2gFAeD zIPg!_)(37eXG)+orKYPqG7r%g3;dSM0RrnPU1jxAQ*oWS`)zq;|OMU}#>?BY~?{em{OlBDirT*KGbTA8T zFQQ&sfYRpwvG*2Gab?@0c0sVwPH=a3 zf>-^d(|vAEcb^{j-2a|_{od#rJA;B{bAM~jx#nDZjUAg~dzE)1k0&s$ANmBuqoI2| zjhww1XUd9ySLN6`t$#oro1&@t;p9!AJmCVw{ccC86i73sH1OnL#Co(W<6|ww5H`R` zZZ~4{Hn}aEDuAe4YO#{aIWd9X#YW%U>p85S=y1ePj9?U?2krqmK^2#D$Cv5%uUThy zaxTxa)N69O;}(qHWGDNRd?ZYTzetDArPeLtFiiK>h#xiu2gbRphV`-A8wCd7N2XVf zy($Xt69%_RKLQtwOeVj+iflKBuUlrbjzJ!eo&}#Bc8{qz%^>K^`R4;e%rI)oC<5gk za^tOVlRu)TH-sH3U>n#Ymv!Nt%;HN2#K&f3kmJfqPq>s4zIBib!by5MAz9+O{q~iz zO3UOM;^{sws5lTqgdKEDWn5LH<>_E9 zdwr4o@j*(qJ)@Q>`!)``s`J)q$>a=lZ#F{C&|9SaEv!u?3dwwYU$d511q@PWJ#T8I zkw5MAUMpjcg%eIMqe-QQ2z7*hTHhO-koMGY5(qf%x-gA;8;mfMTx~(`8AKR+C=F*0 zZ>S!ZL^S=jGeG_$$ofK6B**d9}NS$X)Hn-3diio_447$pDxXZQLgO?EEqJtF?z8 zSI$Ptwoi0UvfG|9DR0s`D_*@*z%<&6poJ@-Oo+`*zn;U`?=Nc%KM6T;uYD{E{U!x? zK&pOYOUqJZIKC7HW^l8~(Y}2b^mej)oh6~-ZT1=l3}+kEs~K`W?pJTr?2?w1^hCMG ztHNcVc%#ooE%^# zr}UAjgxvep+}8~5?~@7d-YUTqcIqX@O^Mmz~Qn#(Qg^yQH2|Df)d<=VU-zU?w^mhA&4H8yTX)!u$j}_`L_}bvM0J(j|F!l#liI*)L6}V?!sqI~^0=~R zYt|JnKpam5JRf_28!QMFLhdd>{@jgK0dX^(3}ho`6o#RPV3s49im~gY*k~)jd)aFS z)(m@Q|44La_*CX4;%1^ zwCe9}Bz;Xkuy*`p*1(B_oOzMsbFLf;n&^7Ju3S96C2yJbV}Q&H3fW9V59;D$Z~$0= z3FTOpnkguN%*Tja8ToYF(IuF`aqJk!Yr9?8&NBp|(Wa zB=7k9qo7;K-X19d(WAvYf*Qp$ViY-V`%(UZ%Nwa@IV`fKk;O^ z>(*pnwPBNPq0ro#mg3#zrOQNW&z>Ud`xE%QV!?;+V=6v3RS8{PW_RbiUu$iq2pV`} zpc90HMkvWZ4N|;$c40+KBa)TJ%@;B`sAjeuUey*X8Lbz!WU;ubwgj&$D?QgPhM;UI#W`mE|K<4r2=_<hW*s}Iu^Xb}p}v!9I4I7TJp#%X{qn$Z@D zZN<_uJU#n_K$IOv``{Rh<{VKm$3wePFg$phv{1cJ^70x)R_X2Zn_WAeUtV3q!2|rq zi<5bPzumRt{O|4B^~KF`yUkB(n)ZinD}9jmMH_DP>E3rbbE%aCvPLBz`=|62th|yo zr|BtRI-JR5d30BDhy_snlKL9g*uM?d!I5-RS4q%*RL`9A3HVD$$M%K+B*84LYkOn! zQG8M(9X+R6#`M6GTe;IW1M@kpJ%tRj1Q!}esN41#cHjyErL1|c)8)srUY8s2VAtfO zNf&%W+}g^^keujDwA_Koi{aUXG*8W>oII`zG#11~vor?R#tP1~-Wk2b)PcM0jZ*2B zLbuu3_7pw6$)1ZtL9ff>5VTpH_yFG-;SNpE_3~ZqY;Q889-^q*EmP$>UE)Ojs#Vax zjBOUzijMdcWv`G4F@V^oW_QQsCJoR2)5wSg{Y2GI~SaNkIrTp=@9O^1$RW92~qJ^X$qJ}86 zBi;7rB{H6SM(=nkd-mXU4n*(d*-(p-^G;2h0`YQ>F`H8w#_H``tFj(5)JdhfKj-RC zI<6y{$?Nd38CwH(+theu1f(P5z{wxXAj@oNt-l7IIogcApPymy@SdK59wKq`dB;vG z944K!4(N*K4|)wZBsSF1Y~`q4-uJOvQ`HqMHnu3rv04V+Ev{J7pY7vlE4R_UTZvY* zr^k-aP^*cINgH#R^;5$1j*Z9lpq)MUqrY8zN%8~+aYC0bx=q?uuZH9EK58@)H&{csmmA$oPi^_ z%qQM3KlltaORtT`G%w;M+~oo2**f90YUtza_{=NoX&01l5Kw29jH`y(kl7>L`c}^c zo)>MHF&(=oB;j%2()QqhnaF+xk!aN5PVdJd@vy=jQ=a~j-p_Z7I#v#tWDagb7P?MW zxu@Jj+fuGs9%}mw{+AWL=?;D5F#*J+W=}#Yfm?6jo<4f*E8AyCx$3{E{kkep6hVih z_loS82@(1DB?5BsR<~d8V3OO{6FS{C=^H`>{2cRDFBIqv*^U7-|4lS=p7QC}ByZi$vUkI--95a5zS!)?Qf&hxP}M_0k5Kn7G%^x$@4cC=O3J$5lf7U23&? zqMgtW*Sx({cAaHB5*LpsQx@5XK5?(F-;Vb$CozbBdd0ULfi_Fj#228x;x)e0R;~k- z(~(Z9qRS7j$;euF`1DEySn!@l^y~=E?)fOtx$xQrKUcXYN5+STtBg*IfIv*5F{w61 z+UMBQ8m*7$jR}UuBi5+Lo*9Gt?{2D}R;U44Nv6-7n>wTlRCkx6%1|pDkao)wMx6BF z3v~9kArc4brszm_!`|%GAGL+LCa0V8Ff^ry$vx^x3vcnbw(^i6O0r5Mc2Q7Ht5R@08HTGgSg|xg>B{GwmQH~4ZhxG_nio$^LjR{!wUg&;|?-J2vzD~!#{ zsp`3<@SK$7Q51-4Z2T!Iv?nq=Q$HF^8RG+KJD=EBW;l-80%?v*K1YZZ$EN79kGpgC zn%968Hcacph?y+xi9F3D$2MJY@0gD=;X|1N(#Nxm6|qBUSjIHHqETCV7^@=TnNwBS zOl`f&u*Cdk*g{mtI>WCC|0JTnte4il{2lbhgKliIg!VL{`d(baoZD2Z*g%?&X%T}u zgijVEpT-cBhZ}wSE@T5|8n+14@si=JLZ{m+H!WGu@jJSmw{8ffMA?U8Vt8AdEqx6r zzEVOjU8wZw)AoiX&b$h1waVu~51UD_X+B`KJw3iqVtrN1CndByg5iB74;da4qlkI= zDC8+xA0E$JRVY}MbWcXZR+pzzWVC>o&8}rK;W8tM*PVp#g|w`hvhvg`)9@annwfRm z0({J)_>yNc5d1_VIG{gv6nYnav`N8#Bkl~Txj3D@6zAPhFr>5F==K1tWaMfo^ON^;-bhF8u932s^ z#MDCe_{O%Sa@1VD7IdtMeCGkQv3av(i3H{~%4~TSE(%OF_)!+jdv?ig!B^@7Uwp5X zWt@+3_pn#Iu+t3*!cmQo->1+73GNZj`COoB#8gU;&%Drb>+s$T{e+6zBOxO_f24e& zamwj2V3bBw;;~nrh8pIaos{%7kFuO@YyGLi!l!)UsXotzu25uV5gvL}b11eAht!nN z9f8LdxLe-nPZBsax6DlTLLK%p>oij7Uq0VB+EpO&Qz1?DE9d79S_#o|;vn|jed4?5 zCbV|_goUIsH874*G*}nL0=eVu3#sSJ-n6& z#iAZTYJy|mZITG{%B#|lik|K@CQwBTxV?`f;^doQd}oGd%VV-XEF`P**}yAMWobh* z>FapVV)dY3m0i7%me;VRbS3FS7IiJJ^?)+iq?UU3#lXbiC4)BHhK^CLmRAve>%8#O zyt4%I4kOD}+#W_g%S4m1-6jQV<3yosqL%fd;q9x!NDSehF526X89(u`5|VPUN$s)Y z9Z*H}Oq1jLA)NMlAP_8Ljy@rMyD?Fs9yr4Cx@|p4_wL!D-;HznvU{7nzB=m1`aBtp zga>fO)-apcbNHwhQA!9CSJ!S|m8djIs;@q4oDX6f_cPDme(K47xcw+_tTT9`xZc%n zQd%#r4~pfkahU!yOl-H6hu2w{eRePN+In5d8$G-lTWKcxk_+^9)62B!_bC5V=0Aw*D*Z93RNGWMTCli zmV^;L<;FQSzih-tvtF=xDa{(httAG$>gUH&9*7UGyIcWDKN;GJ%-Vy=je z;$X6q!-kd#E7X10lElYF(?{OOs?~1vRTI{z%w<*3fF`r40kBssPM9vn2M66>fKw>-{G88; z3vpT$@jLpr{FEJXgU$GMkKi&|V%DQ6${N{15g&+jVRRj@S-A)XC1J3XGfRte1)wEu zj3dquC3^eZr$fBXuW!A1WE9|b&E=ABtREmIh|pOFiNZFK&V0?o|1c``OkYw)t9Y!h z1I;}idFfy((3)Z6T9zI|){u-xRh}g#JbmZH;{%NW#*2ko(VN}5Yaw+T+F0$QmPljV zw*eoADj&P@Xi9r++mt@)LovR@oW9g0Gt!))JS^%lcLIC$d5(G5ra-c~1wabvSsVm^O3Rg@{=qjJ#KI!L({Sw|n3zK}Lv2)d?P@kNJv zAb8E|d$O+NFHPZ)i+VYm`Dkh0S^eR@7o?9UNd<1%+QlDZG~7SdLvY?x`)^PoEfJdCr@ zb!5<--1TAm8Z$}lCzEUHEU!|>l-n6eKYH%wXQpl_DiLKS0eB0+B{A$!qQTF&prj9^ za#7J1?~W{dE~R5A8sFzC=<2gOkljx*It);wsp`()r4n@MG(`wAR`7y* z)xj=uxgw*;F#N^EoXVehbSTgW)dj#(z$5S?dv@1b`XO79 z%d&I>Ft4W{ZwfXann*EEm%p3t&dw@*Lsp=_grfJ$4#hj2vRX9%y|gehHR4OF%)m4# zyTm2;t=Z3%x|I_=@EW6|Z_rBWAM4z?L}wY02cobtw)b>EDXbc8i>hm1LqB~CfkGeN zNs8%9ft>s1DqN2QEbhpM!%(SwC`^+oXz(%Tc-NqhhY|nzk;yZi?7pq4c5+&Q0*mzZGFg3?Ezec9=g<9dh4VtO`)Jp>De@kt>vnFVztqR#C ziuV&aZP(;nmMZDBOU%~etGNp%#aKTRgVsG;rhRI|8G~m{uti>-4By;-az*45!$U?> z(@zZM7k_G?^+sL3oTcP-kU-352uehyIW8@!SX=A}`EhRpxpAMA?@=9b=G1E0*}T9j z6D=kk+xE4QlI>M-@>+WkEc{tt;psG}U>ucra$7coaHE-H1YYSZG&OtrY%FB!bhZ^L zkGsmqMK=?<7};7%<~2ir&$hWHj<0^Bd+)OkGTbsXQdhm(GLk1&B{U{5DEeN(@M~wa zj2ULBk4YtPUlMiH6_&P@5c52kQk4>4+C^KG&|kVci5?&a)R780tb%TqOye@ilH?IL zb8_MxL6--k1s0xk&|*~nW+N`jHnV3Sgcj=M>~4+a03=7>ptSAGOQKg$jaa%N=Q7eF z1KA-A83AfG+Ldy}(E~1w^~l6)7i<>r@r2~-_`wd^ZiqwZXMQ2oUBm4Qn0TB^R{%no zF%!AZcc?AHAX}itJoEU#tWB^`|Os73#d_ZPOU!Lg9m$7PGZmHq3U*7-ZiF%>3 z878RhlJME#&QWq9O1x|5wHG?qtl^>C{!C_F7r?nO?R!Wtyj#K zg%De+dH(iN2>ivhEcS0Vq&WZaf@RKs93x|8Vg1dH6e|nce`iZ7NP8e|t_Gv!P_-W; zev}QSZE=p_nVD@bHQz*oOPTW$ayefF_u8v9%j)_k(Mz)WTzBxkmGnHL!lIa#9E9@* zp!wl0`BckF>ElvJxuE{tIbJc>#p#zW`gk1a{8RZ@t45yBT^zE{HEgd7i^h3bzf3MH zC4hGv&VAV5iZyziAIR7*G<)_b-VkJL+yM&JLOTVkZm%!Ebsiq!+2QhU#)Eox2lk2k z+wDD7Eu>2dom92c67r|#NJ@QFgQhpEu7_q@J2;$K2i~j4;Zn;r+Zrtu77xZXOaytJ z&JWd=f~NJ;iaz7f$<|DIn8kBc?|dDwfsm^**YYZ=*hXA$PZ}(=w1Dl>K00d?oS0<7TRSUUCd&Fl0_mnTRvRu$X5=ioLku_Q`;u4PA*0VoMIJUx6IaAg`d!=(s41| zO)TNP$?vkPm37XQ)>BuM(^sS38pH)n_rvRcTvGV*F6D|`-o|zBy5$kPr^)t!`(}u? zYsNfBKyfjn<<0=9jstU3B*X zC7SP$U|YNUgOn|WIWwq3YeN!wNc`oJ<-k^IixuAEM%Z{=j{02F*6L&Wj%fr6^k2dm z`(xQz717?8g$`N^#MqHIsFo#s<;#zRZmnn_>$<7?P%TKr22=r!JnUo6S!W4!Fr@GpV!HE7Q zo6sa1h7ed^>UH$ZbP5MI>n7MLZ4LIRNo&pm6Hwb&8d}NW!={}r7+^v7u=p{3%Cj8w zDK>O0F*qygye2tHQ{dM$-cM~#hH5#Q^*fD7&yOe%5vn<+6|#loVB|^R_gJ3Zd^*F1 zB4;bcfbq&u$8JNpB&Asuz=ueWDWsu$bP1HECG0Iw>sv$oyFyZVa)Q8!_) z?5f9d#{BhuQ9u)cm7taOB_4t3ji4BM!fNN2J?n7t?vg2zHUhC_PNKsDD`cjP>*&-7 zCd-PxWH6}4ofiG{rLJ+?Va52<3Bo0?3kvDDw=XefEUbch&V31)j>=^2N_3qvm1L+v z)Liw0n5Q=r;V=n=Gg3_r@Ad^;_X&HEpBnt7+lxgRW#Mt|DCM_UV;YY*8*YJ@fRJZfd<{vpjHH$iIzvYF$v^sXpX@`GSbF} zk2hCxJ(_gT>pDeFUPp_5$}W{C-ZEI(c@Y@W!?H#iXnY6JZ1HT0a?)kZd)EeP;mf6 z$x3PtXUYqG+d`f^eh)nKral*WMs2DI4W1mUvqeCIOWy4~i}={YkH^(ee`;O>wY8k< z;Gc?xW4Io{0dI_^M%MokUWb-x2|G^XE2~nLz6a{mHA%eyIv#nQ+%tW5uRM2kl0KT6 zUIwvMzuNBQHu8qc?YP)+vG%6(Iue-Lo4PMgG$SlNKO@*;rKDAXUW|)S(?bW6K%f9C zIv$UQp2tnv3}ez~wAuTTjkeIdAl$Sg@J@`;XpwPOSoT)vA+L*dj$5kT>#kAhws(H` zp>i`52U966X$5X2fq*!c^bVbt_t7+(Jm{A`6ku8O9mvpM)bfro-E6x2*I}yNq9)vaDVI4=f`u* z^PvsL1%Cy(plL_ zT51P5dE_+qw7yy1%)G;NCI=RS_cInG5%?-HZpX&^NqmmfGX?(*wmWBQwV(d2#~y!ehkQEacn`R^_xCVwH8%d+Sb{T z@KV~e6;<(+qDL!vj@Hb`HJIo-({rDI=t)sskFz?fIo0E4Y2ms-wO{VU$l}-<5!8S5`NSGkim@-B%d;s-y+C#I zYhfzys}hRp4L?8QxP^G6yUj2~eL@ahD;Zca-BRuK!v0hLkKWH(T9{ai)qPN(r9^+m zQg>^2wJ}~gNfYE(5v+XYAGr1Wu{tRqM`G_>8Rn6n){*!rQZ#!a%^5=_QoECb(DSxW z_Jw{aypbO#@<^$DNF82SSo;mbhKNP>Yr9emifZ*b*^el>MttA``b2t0VCf0%$d)W8 zd3m+X94op}N8NG2*`id7kn4NBrU1gS_%cf8ns}>zjEt00{fKI3IusPkG)@C9p^ldE zZ!hHZpdUDeZbS~6!w=+ag`GvS;fG#!R4%*pTT)X4WOP2YrDXvlTquO+4$3dy>0s}@ z2AWK)WA#2S8$Gjz2%P~!Kn>&wftLSiGKctLkhQ5}t|*ayUXo$# z*7ySvCEPShpdPW}iKQ0kLy4ysR|@ZJR0$M*}VejN9^eydor zZ37RD{toyaFEFb;#;rEQPJEusY_Cne>2^g$psh+5?6)}XviulfjTz#f(6?Yo?yCQY zv@NVIMeZfN&!gzJhbZRIi*EaTAl9B~gX?r;u}0}vPvI{Jvtp$9k#EJXZQUQtUNFre z3Uekyiu@&JR{7dmt_w6Qm7Ig&+rI|cTUih8HGWByrfqanK;(FhezOy-BM8h@Vgu<( zdsovzeB5seNzKNG#x9v_yQs{87j~aWzmSJvQrnon9K)AMRa82yan!{Ek!S`O3+ku# z`*0H%S-LttJKbX-?=4QOY)VU|#BE-N!>U_86IM_d4CNx1qz;v`8&)+xs_bP7x39`cvZZ`-v_8fnLCkdWnO)LvbVwt~Dqz<^`Vn>U z%$alDX+a=qvHhp_Qr+C;;?x^hP|g@ja2%*~WnHY{ zN35t_g0WuIKpnNMQ3WEH4L;4MA%@tlbaxiV&KktOe@Fd*DB45JzVE*>CdB@9E@EFO=qF;rYjZ_w!$Ar<#X@8MBg+ zg&DKFnW>eLh`l?R&bPx8Kpr3&HwT*@BD0FU%Y6z;#&TcF$;{4$?Ar^3RPO(5=4|ik zWMbxg--(iwy@{%siw?7rm;@QKnwh)HeLGS6=k`vj4n`(sWNa+o+lafnNUHwS8yoBQ zzew2M_sI5B%8PiP-`+Q}bGaYHnT+duxtf!e?N2hX@i1|+0C~8%fMi^3Oh8T+4sIYf z8ITjm#17;jSSOzB|$1rOESan(ROG)lxLJHZ!^J{71U%zeAUe<1dewo&8T%Qg+VYVCDJ| zBlmAHvj5L8vT^_G^qB>_1@S;P@>@4wk<>Mh@Vgjgk8|7hVwT|4Cjwa4Cn7GF`R$>m74RTH5 zp1(Xs9*#d7BiC;*a{q{t=eHPnfPZ<6tSl^lGDlXH-z+k$EI+O?tSrB?%zS^M{})fJ z|3Q-MCzNDAv2-S5mbEfk_jldn`3~;;EUF;tk=+w>{l<{v$2tDz8NRP$}|X z`*sHkuC~r(WIxG8_H8QU&0LI3?;Db_vi`$k{F1}{*8ty7SNwRm0+CtO)!5~mW@*XG zA%54fU;6sxYz7AhP(a`xM=HgG<$A<`PBi$!2l81z{mM31+%17|s^=yvie{0tRbD8z zE539rkjnE3T4z^ytO3&tD>oi%;q~^Jusx)x=96bA(5zcg}=RTqDrvvzP4UfarYKU}>7B!b(AToV+>WJZ=FT6E2^t zwF$ygF4fl8GH5HV0U47)Z0gGjmU0*$TibaTUx0G;KCgVtycFEdEOTv3k_gi%*&`N} zpgot~8l$ZSnfG$1O~+uJ@DDwH)5}$a^XiDn)4gq$A4^Ced8&hmMjTF<%M9rsHce@%!SN4{KsBRpg*o>s3n)cDd z@>$cl!-}Vd?%YO5XiZ1>C=qZH53>D6+AIw@j!xh8>A7+1Vmy%>ZFEr|+D)%P-?Yn@$FAaY&Cmm*0GY2ClBNr=syKlB^WMYHJEN13r zWnv~O|4bH<^(Twa`(^X+2Y;r*%Kp6@l^-@2S$`~N{Vv~+i= z=g(ic5m~waxfLthADe)LtDVU=`G2xMj(hR#ZH=t#bXX8szd2PSI}5XK-w}WKr}v9( zu<`t08ifi^7?oI*x)}$QrHZ8nmD+}YFzhx^i#QlTzk{CT-w=xBcZFhP{plAGD;H-a zGbdFeTZiZOQP?;9-@5pzn2Cjj>nDe)YUOFB!v^I1hvckmKT2LoIt>7PVg*6{R#2Y* z-*U42zLp*rc zcFup?J!A@U06-PKm&FWV3i$Sc%mPFKsE9}?NDom_kWtXlP%&_+@NluQaT&v4;l+nQ-VSJlyb25AEzAv`FB$%2BS06;zg zNbljoLjCjs{QQA}egFdt2aoU&5$V1{H97zq>cInOmh{9j!!sZ-C^+O*Xjoi)LgMSBonWdUpQx;_~VmG6O*P zc0YoEQ)}9+us`#P!$#w`^kfG(o|m+0Rvcx-=MS0iYd7{hgi0adC-QY4n#lLaK!E@< z2p8|piAgL1K%2p}5P-L&WXjUw)p9Weu&6w;;m!qiw*g&@yZpaVS7E$rA5#&zCI5Z# z37c*ajBZ6nVa8&R)0wh3_J8b>wSfRgl^}qY*1=l-7Z3ntR5tho0@y;*J^xiroH1bt zfNEtI+)fVxywzm?4+@2?R?~WXj&`$qyX)KqI^o_CJY)v@RuBEUq8Rd z{ZI`7MCXAP4K{T$_#lATE@cS719S#k;`yz7&j$|z=pJ1>--7@KtS5uc!cnw$Kl$I` zVZ>>uPB0|(q4fy{aVdQ9V&=?7O-+SPd!{Q^%O;)jkRMvo&Kt!--_pSf{4_w8tj~Iq z6+m<@LAC^TFD`by@K0K zs~r>}TBSUuJjFq+&zaG=q!()nhLKH~3Z){}DW>sr*?lUpsjSnDX%;r#00+j(sLnrX z*_pi&ku@l1o(bc-D+H1I7{ue>I;XCk@6O83i}qKP$>M);VZmgIs^_sqEjWwSZFI~`@NsCzPU#T9YVnndyPxbW_b`=mf+n5R zo{#+zkhw!g+N)WAFCRVJ8Qre4A@qDl-s3*SO$e>1pv0@jaH+JP4qv^%{Ee>9=yLE$uI#1AOcm zF==An$;mv#=RTtx{ZM|4GVgC~h3$Zm|K!<=Cw#*57apsJB=tpoR;ddcPhy~txg9f7 z;DN0+g^IYSM?e7p4F^ztGzTpFQvSdZD172$Vv zb6QvU<~>&N_$d9E&mBIogoA-5V#l@z@x~L6AHD2*%yVLg=U|}g!+%jIzuK%M_nFp~ z!uQh%W5Z_=TJ9bI#t=?OwskEb=Lh2boDK?8TgOC0NwV?OgOcknM-6c^3-dL$^w3LO zRBP86phWY(n75U;b!7a|uZhmtW9+as1rI|MFdzWFUR7?2J2+6}^k8i+gL7aVc2v*% zS<4$N1=rH`KvUwNGsF$c|6~C8dJ-(~?mp-Ny|HsY1WOW2-mTvo2yXq(uj2FB?O-PfDD?<-$ zJflPH?e-bGx~a@)7p#$&g|>8nkq`g^bEx1JA?WZ7bgNE!nP>+t1Dq>gy+s!L{E*PG*RG)s6kz|uVc@SW z)s@)gMC!<}1{O1;ag5=~VM3;?)RI^mujIQE=r%XI2*C%bD_}b77QNz{q(@$(nY>DZ z4cy9?>Gz==aN|!AQbC=ejkbpdppkn^$-8(5Z4Wx^`xa6U*5BtvX^S@}VOw9RI_D1tS# zLXpu#o-F>g)b{WC-|MUE%rij%3Tj+6&a?1TPht@_Nwsso@3K1lw9DF%NoYM2*&24Z z5}?!=1~i)qWd{f-PZ53u&wpv%dg2WM_@RM0Kz2KeXV@(eKwAg|Kqy%2YJZJr09q1- z03u0e8*1-hnOl#@A%M@(`|~No^6Nn{1RyMXc#8l!&c1n}aj$(JF2FE? zmm_zLg`i=T8wdcJ^w#oMBU%42Qk)>V4Mw@y_~Ao3&5e|3<*3bK$-DZ0-S*Fu@()Hz z{jZT4NTGKcf`-D2jOtn&QXikP#mV*Ou9*y{t`4b6|IS)wb!iWl(4z;ptUv(6o%+Xc z<@uc}C^FpV^q<5U64f=_poC0(;cWQ+H^lt&fc!nuzoqnZ^$m4Rmo8Kd8PDdd8%1T- zqxefw1hv<;e)Pg69i6<9=jonAZna6cTP}I{MJg509-Dwk!M`Wz|HhH#{%a&)ZHcbD z>(U!UozVBGq6}9a_~n9J`6VjTE_`|__dbUn^O2!Mhl00Pj< zy&t$R<&U4N*W5C`&BU-)(MF23ub^bwPisJDjfmFnO60HCV}Da5;gisNKlo(z$V%PO z{zBg5NEdZuAnqrWK>>Y9!F^A+qWeCoT%K~>m}u3MVO|M1Qu@qKwbA5~B%g=tUasedOg&0Q|NBB(08z6pl_M6unI z?m=pTTfV8+fcYQoBY*}tAb`4B@W`(oKW#TzK>#eIH!vR|fXY8O3ga?Udi%-~?anO| z0uZ_H9zxo-Avx5D8oUO|86c;_@-;H8e)|k;5&a}HX>qDjO zYsL>l{y;_zMfQD-F&H_nK7ZBwP}`3%sRK+};Z0#{ulri6>T=f9v8zMQyOl)n!5B`q z&3kv}Ps4K^S>mo{AVfT|l!^+d%S`*6mlIq;ReZK`3-i|ORh*npTJ%~y8jb`huRSM9 zGVPa9?2b8ZUh3TNeCQ6-a1iDmqI{fxY20&m_)25K34H)&l-!V;TVtcb>t5X`1@4v7 zKn1iVQIU6Vb{{V9Lw(8*A)|_SxL*b`a^il+Hph-8ZzE$A^*%J468_Z93~x-=TTGQiSz;kAcWf-0!1DZOH=C{l9_ zyQaB7Vs-G~b~G(l?-rTJZ52oRMk~w!c3#Ko8hOGEOG?nkg6Uny6YlPz=Z^B1jwqja zg9dZPJP2K@rRvAiot{#Jv_m#I6Ph{_t zs7r%QVnH2PF#c8~8Y@GWJ8|0P=IPL;ZcAjYHQ}4(5IGHYIy`RgWaY^?$-LrHR7+2< zhNlO$MNP#P)?lqL%KpeM&?R~?2zi%Ktc9YoX0%BV8+lJMlPX6-9S|qsNra|ddT&?M zwynE6igz%Rz?JALf^&oG>-c-?0VaNPM$8?HSHuhgaiFc5lIQ0fzvK2aGJ{*!%tu>y z518+el~)X|2&xUPZ<6lq9+>h+`;`y?#~65J@kZjG-8+5Gaqev!Xb%e>Jn*mg@^Hqi zTTjTh1kYzccZl_=bUFr?*CBW3VAuN9)+-`c(u@1?g|s)n>8f*k0|anO*^r);X?~+{ zDW}6fklX{$^YN_s^>I{Kzw}XLEKS^tQV0O!8Sh4;SzdAd*qOUaJ-K)1veE0at*olW zPEY-OBHPlftb-lk>}Dsq$m$$2h&bmu`G4meNW5Jwr)&7y=(ERzK$`%Q=Ez_tCQlr%2+4i75Jom?Q_;gT4q7w*L zTU$$4`w}Fh$3KTsA!o{Tc}B2(^~C_yJ<%miCk?3&*gSTiu=y$--CJ@^kX#e1vqsyr zdj>8VCwUIJLTY_}oG7tpaM&6t8fymBu5MpEW0mt*uBtqxb%F=Rf_t^}gOPPo<_zJR zFPlm0cUc62(#CuQX z2--4^#=LJbPyhi;&b3|>6!rdVzt&)Xm6Lga3jxghYI|OfD^hUd0R&)}Ecn&>U!Mdi z`4)V{q6tF)C1dx_OTB;O508;)C-K7N+T=*)4O#YBkf~JI>5ICo@(>g?-1k*!V&<5q z*JWcxn!+D~nDT(%q7}QZ(8`v{to9A3EEcxwpo1igqtb{t55}7>*k;MT@XgxeRejBL zyL*$vSM0VZwGR9wZypx7{BK1AIE_}zC~jXT=+j<8AN4lIHjNXIhUT{}!yS{}Jy5&@ zM?(N%MQ;>kn?{*}nr{WPQa`8bEvClgD=$y z|7VMe(-Sv@x0S4I0MmFq#!^4vO|n>~sg@rB^fTz%^>H6yV!@X7>xdm7l4c;+{PSSd z%P2v_fgk3oK4-huvv{hyJY+E0|KkhTCD*kWy2^Kv)A&XSOVOTY-98thv-E`$I{d%Y#EXSTVmiSE6z=>%$r4Iw}3bE&K)us#$kXMlecEOSDcHz zO`#*%ZjvfR@BPt~#9cv0{`!HzR!sXwRqh%Vb%{0aJ+_+8fpDeE4~twX^Pes1SaVuC z975f+4pzDlBOdBEy4$)@NHo5GEgB?zsAIL1XV)j5vwQ75KTL4q_mO)yAU-vJY09+b zxHAFkiL`Oz$oM%7Jv80;0%?-Lu|hL()A9RZc`AQScqT5A%qT(LwZv!X6!{DafCG6u z8xn&0(Q{cnZmA@$7l;T_UGqI{@Paa<0*L-kV4Ejjaa`Kh!9mZXz2gBV2IXzzr3#eP za0y8Ytkbovp(`TO9fon-DWG^WGMC8Tt-X5p%t_XC3DrjEl8zR!BhO~W`@=FInV_=v zDHIQW5u>ws8Y|HZK7jM3-%psTHg#D*__KP3TAGqqABb0#;eMtKfgA*faq*dKh$O=A6 zsBG>9goi;)9EDUZ!5c`saNMU$Jb?SuFJ57!3Un#OfQzJKS*$;vRNwkqwJLv$bvAlk zqsw1qpGuELr@XaJe9lOti#zssqHQ!6k1p$~fB1%7solJDxq1T@Lcv%s=squx8MU{~66<+=E_k3B}Wu{4D|E`boolrfFw#xnV^iq=%WG3+DCGf-O^VG*PeLtVz z{I~qT{wVYpst}0aM0TGYi@xa#|4+uT6&-+UEvTgT`~0VM6y+|AsHb|3EZVS$0WNVo?QhS4b^KVw?G;w3>p|zE z$jKPKG+R#2TD<1b0`E#BKVUK*5Tu|b3v4S%!=DsSH6d^FiRbOqXfWx;VaK*u32`Gs zQ3lK;dp-1q9p44H+L+m30Q6)oC5Pne53kgj(cSe|#cPB2?Z}%dlJ}o2^IHsqB_}^< zRUPT=FQiz2h&vmE9gz6C-HPb=%JUDrkenvM9pCHETIcCfdcb(S2U9to=VP@w$;3(8 z6mDN|mHTVYaP{EtXC6b>r=hSNKme-p0tlh?=5%VuRZ;b4oi3S2K{^jxdKW0hI={MI z@qn4-HcPwHxyMF`nq&^l#JJG&O25y=#>!tE%Ln9O-TUKla`` ztjR6gACH0}C?E(Ty%(uU?@^R41VMULq((q`C(?Tm5Kvk~x-{uhL$A`C^xj+O5Fq(R z&$)BYnK^UDGk50x?#yqV=lv&7lKsB#UTd%Q`K-0}Ue`dvDsIDG@LAn(iebv8&jGs~ zYNcj=3+`qI2N~v)WL3lOV;2!15_Ac z80-nzV0qcpmgZf32lJM04aeRYXn@&qyxILA>(=DjcR=@p_A{{J9LX-k)codbQ0PX3 zR84ThD@aeCP<^g$J&G+H`q*d!r*;?(xbQ^$cIH}KnNG;KLF?0uO8=^Ol{+$oRHrv4 z9P=RftF_dHJNWMcbz+eSNk+L8wu<_N=w!)&_r>{h4FDgNMw{#=C~e(QknIc{zQk+$Wb&g2`n=GHM#2mKqW0HtZz zvQDjVji_@(Ucp7&Yq%r{Aj(f5QkE2}*$5H?i4BS>i;-x%oe7@KMB`eV1*K;$<)ESc zrQ%Sv3NoiTab1N>juPXDMZL*?40zPcoC1$f5c)XWwwft>+j&csRjSUTVjf$A?2J=i z7Uex=c79@mVy{S2MJa();&-*?q4LTKEq7AGUIOtB46mNVw+3zq;4AcW*A(#_Y8v}; zU%r4!JR&dP8sf2b#Mg08m~5C`I2jDHYNhln?5~7}#1WTOSy?xo+_t9HEK{U{^?E%? z#X@c`ewd2byi&4B{?>I@;qtApmtsg~YB0D# zkcPHshq+)>z}2SU3_y&6IRRHoTlXv%1;&H9OFK`}pLGww zS$nB2oM=9tKjgKLq=@O(-{fr_S$uGA**v)&D6V@cXL?FLeeLc;hIYLcTcmM;?QpTj z{STII8osw89%Jx?^d4^j!<}6FZjqxEC9NI8vuGIMx3b7n0kJtXO7|ol<pvLa=%Lt!CqRCj3GVBIhT(zI+qT%MmRFyyP~rvtnNibZ}`eSuDL zb?DB^@Z^&T4x2e)tmY$Zg2EQi`7TGy&!`;@h{s?YTbuLLU!!)?0ha-k5%3V#7Y#7| zDdNLXi})l2Bsf^tDl*mJy)GJA3OSC}!?#>h$w`#N0vlBa;#P`H{}2 zXRq>knu}{%LmY)($8w0hZ(kvq@$#wU365^tUA@Z}^eT!aB zm*vEkjpd?%gCo*0Mu~b#l^TGL+VnwRGfCY7U(Dbgz zC}iXo1`rBnNwVq5vj#KzzkNIB?Ue6=9VL$jNX9THkW1b$3=rAfsx!2CM|i+r%VBIb z6G5PJMA%i)y+R|yS-OaP~mBiMN7u0QVXqQ5V6!jACdAYT<@BCUbzsSr`0KNLJA z9bOx2_A|IPux}*@5$JS{d&tO5nJ=mQTP2GCuu_r9GvZPf){{IIxjz8~NF7kGnbAS}qX7vdV{k21 z%7`SBqy$+*^R? zq|8k|>sT8H_3yX1T5(=4NTREctTbC~UDvDm2N}&2N;Ke_W%8~5TmcDHuq&5}iE;2Q zI-Z*69f;^Eex-0t3okcgWe2FZ-dd(!+p3vc z_VgOIqOY#v0$#O#MM`kjH*!UmRw1y3Oh+=)`Eq&&C^We4RH;Jdk}kD<80~|If;`7$ z;lPK3j#_yFlq~~W^M3sHZziB=us0FU_{Q_>kB}MBDaUs6a(&zsyK@_Ja|`)><-J~1 zUaaxf-q{wKwPXqRhOBj(PLiLidB1k;CR`uRT^TW;M3iM;E1YW2R$ew%&e9MjIS^hb zM4Ht|8$;4841k{ZEE&Ke52H#xu$++Z?aoKJ+v|m&1q+;iDNJhHExx__8bsQAoTFI` zAK<@|o4LnaTt3S7wb9s0S%hj|fw?hn%7^4sh z;SUw_G&m?ZSLpL7P0Uz~^h5*bN2vPoWn~ey(ax76+{OaZooaQJuYYK&9YwwSNJBF8 zqGXfRAYjXeTd~T9oAhg|y_GE#2eVe{1{UNTDYc)Asfs*)dr*gMS|)ClHMUmE7{AtG zD0undg|e6xk(pON?>_lsme{^wiaxG!Eb=XDf(_d!zw2pZA2{V=;zlif#IJ-QF;e&Q(f0`yY|Y>w%7RJV=~$B#?yhVeSI^R zfvvWu3}J5*ppg3~>f={|S67^av)c2h?=^U|S@}+lh~KB05{u9tG;H^) zB7Uj+Y=b@3JNm1JV1+Hl5oGDz8=s4xla*=VO%KMoTvlz9qitDE;jY!Q%qiF)bVB}e zbhV8nCr6twFe3c~4Oq>XcL_E2oPgSgd6i6>sTWluOv9gE8_&;s`%VpvU(xeTI_Zd( zJd>xh=U&5W5N_~iDXFSkTVi^~bViQUmJxnDc_q^~v?r(J7j;|V_M5EaGFY#0*QBk? zYZ*Qj@0b>FHQxO+Xdr!qO+-cOwe83)0isWc+DNu)(c(3Cf|Weu2n*w{d=9OPs>iL5 z`wzffK#kJcNp2#hvb%}zu?t1cY(u(tx-%_uTwYCTbuHg}raoCxz$h}~tvb3k{P;|w zwtvdQpwo^??y#KW&9ZQ-@l@Vwe11%>iyhYuy`(&*vKQkM{%u&jC`d=avC~nbB-tQu zWwb#T8{5&vn@@t>W-dg@(>e6a>X8oQ#;I0P<%rOonx_0jiAoJmuJ6+#H-RXBy)II& zf-}ztC?tldPV7vdK}91@J25ta%YN{`bj94fCxaOwT5aDBF4?(oQtq_Hjs^rDe04Mi zTNz{NS{zyw-TJ!gDStFSeUOXybL8%CQ}4`6OvD%H95aT$Sum5|j~S|F*W>h85|V?R z#!#Q)oPs%Ra~Z@H03z7QO~{`%QT{+ePUR{UKz^U(&HqlWvAYp9hB4c@zG;@)z#X2d zbu>U+_v|*XNPq{4Gx@Dp3Jt*f&!_+Cr%g!;ixDEr@(;V+Pl7iOQAh^T+NZ6I@v8z5 zzzQ;8*_)!p_)O(|`gA#SF=R3C4FBV*B;7!!N}NXFq)Zo+*`<3=+ttqb^x(nwX_$xX z?xNzpWw5z_Cxe}T)gs@EiljV1KGCvboFbOaRo?|UOn4}hj)4-V@YCJtS=oQd4?0t~ z26*OnxZ`)V^%=Mth`Vk8E_=nSQNaC5tn~Om<_vGqfKDwhnV#$o$aQeQ5Q=ho+}cy{ zd3D5T_%866_KSuy^l22XgItDGlx%uKSeo4}Yiv!fe@O0@?L*>)X8>~6_Xl}dXN(2% zS7ID04kKX+cn}7A?Hl!6)m_(is#Q}O8T0!k-wzG-mdeE6(r9psdcH>_WyZ0-pEg(` zp{Sq^J{2*N5x&;Q4$6=v)#&e^JDfEt^^sq+mXfIu=wG3r$xJ_nDMTSVv=}Yw2pYqX z&m9Eb&267hl!B03L*YLGs_y}CvF`!!k10DERncg`4c&s%t!NZ+o-@j)-0*0U77+u6 z?~_(y2-gZ4;FqJ1v8Z_?=SQ+<%sSiWm#pF2mB3l{5y%RMBj$zs&;VSGDm38!w^1UF z6-uX(c$1K62S|f@K4u0q)={Ua|Dt2(x6ZZ{XRYa!4myuS>oL@S<_v#LFx%yTgop84 zaoBY_u)c+KvPn9fxf3>x+$LmnX_=B zbsLzBh0dAVvmX(L^(ztE%=fevlZ;2(M0d=whjcXV^q}qy*FTn#Y z=bpjpWsir2BDlA>)B2KKwZFu_P`k4tRAy(}dqXegn;xroF`^#a1RhKR_vsBn=eEfW zSKP+6b;h-;r37BIg(-vj{GXx$4V^=1z;cf=8UVLJ1DZ8OsAE&|CMNa9#>BtqwbKPX z=bi&8*Otm$VXk;b?@uAG=l|q!6ewNM-NgRsOQS0Pl(zr{p~vyP<%qI!du!IvN1yLT zekQ&ncZd_Mt=i1QTcXA&%aF)>rygfQeUtCOV5w0{L$~~p^3`jXa0XaIB2@cr_OnTO zHlLSs9Vrq}uDDS^*FjaqK2zWX=MWD6$s2cOTX7ioNOUZYoC`tBC4}tvsuoSC=$4~T zDAqi1XBP+K*WA}{2xNQvaob&ZDf@_~G%1B8C*>G=mnMF9nw?7bvj`ouT7zp`p6hH$ zu0vtB@HtlMjs8*`KgW5TME;6H<4j8UcH;7WuKkT*j}Ku?-IHndFonK|#{uNz)L)~e>%laRQ>BHd!o$;JRAO+fY^Pf-pcHb)CbxU5ybOtn**(BZ_s zxGqK$2y3X!c7T&l8`hjfbw0~o9P#W`4>QZSFhiJre@F6;fG#esM&zc2YkSE((u(YDIEOW(k1T64-k{F& zuG#6pf{!}0Ha1JUv3hnPxKxm7u9MRzG@@QoSsd}?`JFskN=RG5EC_i3L}EK6W1|7Dd4kb^^&T|9 z#0@r^K2%>ZNVm6mr`57Ma$8KjNCfM>fLfi9CYcw%kM6t0WW(DnCsc(k0~13%xZ@4+ zhwz+7$wmVYqZpFkF+(BDz$AOCIZulM)aZHYOXkTcbNk}e@(hWb4?Ag(_4Lds8f1v| zrI;=5ZOIIv0ma4$Qt+H$ji<%OJpVV_RV?Ax=5<4SA_9^kr5+lHA5F!gXBZ)gM_U4 zGL1>*iQ)hiiF@5%z8CY(WJ-ku$4oO#vEyHQ8*5_`oIwdC*bAC?jt_f*>t7)BiZk#N zQgL-Oz@QOhtli@7?N-aqtcpuA%N1-c@ag6x;*hf<%a`!wXKnEGS49^~w~7~a((J7K z#p}8_1788i4={|ZCltP5IRsp<(h&Hm9^n5#UB!PngB@CwA4i|Z)0r+sy%CDtenpd@ zmYiTJ-^l&TpWw4PV94HBCkiEm@igjZe6vnfBi7L>V`VzvPZb_#xldqml8HC=^GVlD7OOYNS{5kcDy0$)k4!{UQ+=UhZ}!>cFicVzNZ@&!yBa^= zvm&-R)?MgDtL^eD!DPQZSQ|ypj#4cwU0+9M^@z~c{-Uq#ZO=|P6er^j*_{Q!xQ{u!O`HBkjhB?!5Z&out2qfU2>x2y zD(f8s?~PZPoR>X?S@%D}5e1I$a#t~iQ^^g_%rBHq$a#@-b`aT`Q@LnaT;^9f=F)+f zXWAFqj9(K-xI9J-ZNt+C^}sw3#uGCosG$J`^=I?>EPqdZ$hTvN+HLu>aya`% z3+{c9BbmPY<>^(yIy*9PHMaC?PkeB(9T;Go{g1}eBNuEmU&KTIkCg(y<2I8Eljjd5 zUrTAjL1bC%wCxD4Oh(o`nd#@d`AjPcq^iVeCvH_K^xQ^Wn7?11DLTs29NRatKHZda z^qIUwd&VH#BC&CiJZ%?V@p*nXE9>tnAN;f8-GBXhxqcRyV(%G!>Xc&2s6ppTZ>>r; zkrw-;OaZBprYY*0B(7}_KClf*7)d7)x!z7P3GHy9hjB`VZ(eB$rw;CQMVhVm#4^A; zV3w(dtyM+cu^wJ%hH&SFlPA0~J0kK#k%5=Aj6w`q^s}aPXS+!@XCun-<*!{~^ud?El-FF(aE0j& zRJn;OqT}r|+bXu{+l{sZ>yN&vU)=2W88ntw9=NZoDd-lj@EaHd)M&WNXYmh0CchbU z{q2I-9}duwu93y-=V#A&;)&HLieDG!i@uBh;RdwRN8Z%g=`U-ui&W z1)aDHOn>fDpyz9_bG`EGT=$(qw$?8yRM7__z;x@$^)XZmCwMl2qf?)k|0;3%=Xzu! z5pv+n-o~EQZ$D>KgG5R5%kCmOfa!XZ8SOpWahBY0Z3n|Zq{P~Nsu822dwS1h1ZqGF(u>B747?|zR&0V>T$V86{nR)1F9xWlHUA+cl=0<3TKUz-l5573i&MS!~ zO-d@s4JB^L^de*q#$FhTpw^MiGBnqGDO0HQ@nOm#G;Oo~=ydvhwuj;z?%7>in&1@d zQs|ffZ+oG3QV$8ZCXpQ}FCzp}qLy^p&w_QEu@G(y`WQ99n58Ss;@y@8U|OP$$yNz=wauILSAKJCh* zvuIB&RHYEAOIwn(@7V}9w-K4rr3G8p*cs#Hr{lo5bzS78o^Y;GVXI`0QF`J_uk~6K z{Cj{Rhx-Cd&xX9XKaBccp)SW>g?EU-4M+HUFoM?jS`HOH&+f@99L5!#ba>oAV-a@7kr2 z1U{)D+H^4{0Wwf&5se2vgoSz9;*awcaf1&Oqx_6!5uiDd+%|5OvLw^;csUcp%AG54DJk#@#oHGi5Hd`)O`I( zdS7pURX@kYMpf=vLIXuo)8P#^&YR1fCe|ldSQ!$?0Y{8UxN_vX#oyVP{&~m|*Dva0 z?L0-8BM?D5GWJ>Y-%X5vx z<8b10GzxWn|{+qsKXj+3XMv`gzXcc%I51bX= zp*_b=K%Hamd_(q(m4*>R%Az6DX=uQlIU3+M-vrqwwmIF0ohi{G5?vxtJ{WK7h4Fa7 zsi+$fL>Ln&58v*G{Qvj15tuLYoqoeD_4YfsPns^b7x~qSIEyn7YDna`Z^ncCTPDRi z2M?YOueLn%!|)?97z7PaSNrdqAJG0s692jFZ{Jn`J`1GM>&m_=VP}#&HIG*$%CK>f&?$Q%9fanZPVHW1N$uPI1bP=f-luE}RcRev^ zI_sJk)DJ})h?VPNxBVzcFGaBmXOa88*y{+$R($i{dV$r_o)hBgyJ&!oA@a^2YHC87 zlD2YG+0_$mg6mu+gs5?&EN9g*|3OK*!!}l(7X^C%14uyoKeE>>2xad zIze9c4Q4R<*Va%Fh6}Njc{QiH#4Qbw^Vd8&D2ahP-bMqSR?*s^0s8iFhh#dAow`$X z2nBdUW5MSGT7{h7Kg82!rst}K0mHyz)SP?P*3)QkuJwDPFy9Usq@#+m0L!9WM?c&z zdNL@tx`!(!&UR{4McK9T5C6FD9(GL-kJoJ1wdkz1J>`Auui`yqu9VwEu^|_eEPL!s1kKK_NeiqyJ;=ry!9~V?c!^~Y3Ys5=`|qx(vGkE z?~UdNBrG-Dm?oB{ETgZYQG`@`t)3m9DY;V*H95r=O+0dHCMGjp0kjvu9K}WjsAZOR z4dLScZTmgFm{+0{v+vT7w==}{a`(H^lq!c4!4yIt2 zW-1B;Zr8K1z@7>V?`K11uhw9UX+R7b;Qio?4P#8Xk5E1ony5>Jh*Z?|s%hjE3&Ud) zU_->Q)HY;=J{>Zn@~yD)SAV;$SwGTNANRPw@pc=-#!CqMwujt^D9ryuNyu)CSm>({ z&fr(qy^qS0&*l;NI6pe-4?j$5?y=jpj1O);b6KoNC$>4$6tC!EuGyDV?=(QOXw2T@pT$6;S+Y1Q}=yW3{9_}avUW49| ze(+cF0738tO+?SRZNfL={iRP@k-EA+yzc?ytCtGd{AfU-KBOlX4LI5uv}@#K!Zmhj zUm>?u;%t_RWx6(FmX4SHmEA`x5g^uI$^SxqFo)oM7}2A@td;oNuNDxQI<+n&sq}_< z=V$^EB%yVfw_Ro-Np|9}>d^P&bo2;0CI0%M%SaSN}3)Fflz*(>&3`-!qiBfCe1+ zYyN06h(u`HTAM;qq7T89{P^jnSY#Nk*_^JuGevl|D-HIJ7qCeZo~Jo@#wSoy2p=%j zS5y)|>4mDei5`&l^!@f>#Gxo@$Tc)zgdDzqSFeji^Sz4(YW~r&d(M>39qqY_OY-Dc zVi)Fja$(0>lJsZ*>@9q|W7zXBGutIor8HzsE8gb7HtHe)=+U`lY-al8s!*PpI}!Bd zg*p*z8b6}p5@2DeKAC3!Q8R^s61zB2v5&JgrSr9&o`M=H3#3MR&heJ)5Le!m9Ft5{ z1YHK+POHc~Y23WhO?_6a*az2C#wO&JE`^0%y0szdNZS3E(W$?!(WC>~F4i1k&*3{% zT_!IkTCL&hOGuulTM*?^L(Ltga;IsdfmwavBZJouT_MgAT4+Er_~IYv&ry@UR$eLH zmfYavk3kuPm5sg7fbt{rWR}x82}*VAd6dKw@D$_e#D@uT(hSXyXq5Kx$$^fQIT0#u z6e+)XMl%B%5NX&5JZP~wzlL%9q$`p)szO?4QF-koQnwc&_3 z3&=jZ1^hJz{DHAF;eje}p__+~wK96KRnB{5y?kmo8rPEP`(BiKDs;;iIP^CNQdv{qi>9#p8Q!TqIFkZ#4wFYfMVQff^q3N@jW;CGSEgGg2Jh{Yw&S z_uI;>5v%93DA#<`hb~D`(rjxlI~uVmOn$(=I3?d2ba*@~cFv(u3s$oiwuu!qenqnE z&-if=GU|ng2Bi34Jl%zHj3#^}E0d(rm+27WGSKFtf|V#TJ-TM(hF`(7H&)^ZAv+Q6 ziaVqq&9tcFl=u1YI85;Va%3yeprlLV=%EeiYGp0VzKk_lB>%(RPj|1^6|VNoCf`5E za>TbBK;6VSEFmx{xzTd!^IE|lFhk>MNq8%X*HgW~p>xmqFvBcTyr}l^JXLbV@@mMk z`Ck-i{O%+wTn7Ecib*}%bHDJ_9oGMA7f|tWN#Tfb1uKl1j!G~}HXv)A1UH+839^m}j%t~N-hsZ(1gn%)APVpaS@l=b^% zX^z}H48JWH<$Gg?i5I`GO``e5d8o_|Pgh2fg9E?p>$or0dAwQ$vi&r9eww7}!>i@3JN2{FT$_Aq^ z1ik`Ga%J(fP=`E@HY*l39=xn&;BCSQi1{c~=gwVzgD*9x4;4jsEdD%~Mf9z36Na1@ zLIrTV%RkRIL$rGDuP3nxXm1BwY?WQ+SgA%CdLMjrqYd9yS{q-FW*$xwYG;eRPk3kYg=5gTcyqQDX zu+yje&lu&t%KD$Q+sx7i3UpW^rKdt&xNIU-RlO0pw~Wpu-$+I~(?rmGY=b|K0^Qbq z*}diNb-Ba=e#LSuDSon|Ml>@RB_{+O}; zP8wqds%t=huKljR(0=1+^_9O%#Oz%$o82(G@|*V6H+WW52-0tm-CzNfdx|nBnOtQyvgJya`R~~GDsusS$|efxjHGR(H*5q;>NHQ}E^^GiX}k{=9&*Mg`(1q_zv< z{IM*_nd&}EP=lec$ULpu`glmr96ng)Gs3ehF1?=tTEEd$K?e z=}UQa@IaYrxdtU%-z!a!>n%7Zq?fC*R?Ctpeed^gB_HEfuUeBkWl4q*o}8^m{bhRk zugOSxU{ew43&4Z94sH?mG?guF2~etT-eC>hLD3(a zTh?aJzRTMTMB>i7o70>6s5#PpN5Z^&Bl#NkM zV8uCmS>Bwy^=57T({FJ?1YOWBYRj!Km*Ria)GueuAjdsTFL=Yu-0(B?EjOaxVbtc0 zrfEoLU#SKPL$ql2Xdzp$y{@O0mC}ciwhPnu`l63?KYl*INy$b2gHVt8nw!8@RBV?! zZkS%{66-)Ok|xnTM2S(h_FF`U?dOON>#y`-c=MMjBzvK_a-kz0TW7v5z5{0w0fYZ( zx5MfFY9)!J@~<`@lw_48td^E-DuvVqEFlDAYoBVS1I&aj$gFav3&#U9j{;8?MtE0t z#F&EGz5{q#h5thEnmUznfi@0Gygg4)1KPQfBZ6xQ%1b>vUZj_ME};QEO3u3>;mKDq zOfP&agS)a{TiDya6S<7HjO-^LSi}+bWCt1Xm=723V>x*RwvkK&j&ZR!TCL8Y7NI zj{VKRG*nds47zWge+TMV6&Ro{5c;>HLeaBHYT6~>gj+`;R8kk_BP4R(E!j+D(bot1m*bw4S=tr_#q9r z1sK7U7#^JiTOy9{3!nifhoLAmAoI8n4YGX+jOP>un^zro z!O@GIm`Ab+i;SZRr=QlCRU{k{!XtztP`iv@g|dJeHZBpV`mPV z3bW32f$6T>!DqnS^)c8uWB=1qyA(q*^YNYDM+3_KO{e1j;~PfIc)AHs zjtxs>r9)XB)SZFjF|5K&9?_khJ0{Q-b_J31ww;&#tPTqbN+EUrH=G!F*fpp>R^ zV$<}xx~;EGqQw%GG6UIEG`0u7h*#g%DCf;-SU!&;&^&>NE<^q~bGz3+%!me9VIBxp zSsvBD2DTXF{8SO%VjqBWIpqhAH@Em1!l?S(qoX0zQTQ+PWA>|(M$(Fzo)b!k9_0Et zzUdldm!uj4{CY3|h$83rV&3YTgs2CV&gUK&4wiyfI@fbT;Rr$=LzcDne&-l;)J=1Sp957F( zSpqyESe-uDqec0#kAwmjEWX8o(SRi5zQ5hq@UI*tvm%cBZC_XtY7er4uNC)mAAvP? z3|LqA2G$KQGV6u>8ms@E?InJ6pNMWUMjIl_A7Snc?;W+*9OJ;#6(GfL(Y%yR{z93%dA+sVIDtIP2o!FmQ2bw2&pBvIg*KBRSU zdb@ltD+>eaIWVB!9aVMz&p`d(SuFf#63Sn?nv(>q7kxD5naHQeSrkm3*A#dGD)vMN zYI85F2%T*Fg_+|j>C_rq+KE5NOVZ=-+R3(0?`>OUc-keVEiR72QjIs0Y z)5;KoQ9Ac+9kaBwuEtE_>B&71KA52*bjuO+&3cfB20XvzY;Y5gRQbVkGm-sP0k`#r z=w`6JK+U=T{8+ZdTzQ=Rdurt?*4})SEI8m z;=#J3{P>(NqlVYCvW*BOOKO>SE_GOn#>U4UDq0s+Gg?&!;1P%-hrVuR7!n=FO2|-x zN@UaJnym(oES*^Je0yh5uDO&z{0TiRSn$R!9-6@4(9z*(|NR?t z94C1TYDv25^DOmJWbHbwLE~O}Un;b*fg(Sf-@Jd~ zPI39f`S8S?6c&a0tWB-OEnN|owZ z1uuxjX8I=|!Vo^I{hZ(>frSt)0uVKu;T40Max}XQ9Ls>bgq~p66;Y!btMPU5x9Q%^ z#^A|Qk~%WRFlOcH5)yVg81d6My$Ro#_6ocsYoAo2Ib|0x&YtiYixBawHV`1R=<`521v7GD8Ns(60T+eOa(Ehg)6-*X zvhJt2;+9hwFpq}dOhP1q}VkVeaF zmZaEB|Dt8RB&qI|i!lE(qIspdqzI~LQNVqH=bGKcUSsk-U=F2Md~Dt%kYT z#{29w90^u>jMz?TO>$LSbSO`7mrlOyf_gFz!tW7C6cQ4O)xZ`0!my^FM|S|gEJrX< zbzsY(YNVtp;(2xt4xMkW?}WPO-`kev&-T`6I#N|u8(?E#Yhmq3b*Ip~LldTX+ZJ2p z2iX%Yy6TV{X~|E_CEG^i%kJ}7RgmvvTx5Qc$D`I$tVWCI5}iVo$NH+0;SV6B6kr38Fy4#cH+$+3G;cpK%eDQgKg-r)(%+m^e52AG^M+8YzL zjl&Fv;y%b9T4^toAR4rLEc2hoyT6l?xno}?Le1fCToH@~NXAJQ#2EdxH3=nu>mXNp?M=iqxk{7DW@N(4mV4_xd9G$**bu~qYsvpG59UEpq)05Hp#GRAm!WX zD4PSapNFkk%ES9zP3&*=AU+m6-Etppnv<)gmphfB-I#llIoTF*430tAoVCI?h-@(e z8d`NY=H#DbOX6PEj^DZzqn!@nW`KCByF*U|dihlgA{-?8a&b=itgm|n)f>{e<1L*r zW=yZ5*yXqBVy8Ih87Jh{q(1sH7CeZLA9i_$KzWPTF;}iNk4uo+;hwV}W>Q3u$y0ez z2$6w+@2FeHm@n+w(Lw>|m+WYmK7$Lc8$Mbmu2OKml3=&+@}+H$!i3^gcP=c&&(X>i z!!#RW3@7;ve#=|0suzxyORe>q*l7hp%@Aqp zId&bwz!Wm?En*;1tIh2up~9My*lEK-}MIQ$Q5ZUSMPS1pJb1w~!cwrzSs26ob3 zuEsMJj(_6FnM(L1>vHHDak?^W7?PJ+UDn5)#}Ea6@RUlyShZf?j@)HCeuaPM5JG&c z(DLFuf2toO0D3YJCIz$A+xFG!am}gAL%nk}=9Q9POq_{40QP4foM7%)YkP{=pPFKC z$h1gv#4`FX!^zJ$BEHoK{t}66e=bKvevWoL%%ZgIX3#Sep#5oLkl!Ze0D{j|bnMln zT^;d)fks#EPLumw{$#z4t@X}iE6HnP&Y~<17)8V8|@?aMc?r0$P_9>%K=(szVMLK4ri7pLyi?0pYdWIqr{1CwO)zq)2ye6>aPAeWZBlW$G%^@Ogp6?4r;*+tpguir2DKXZQtK^}Df zUAu7qoIn-mt|4R67$~h|wywl|kQHN(sG|s3LvHQ+Iy*|#Q(r5(*}D8FcF7`&Db|8X zF5v6X+tI}v)y`*meedpdGuBR;sTi)Q zf~={APm|LVJruh)gY`>^do5;~q4t$7-`irp1iO-&%avEibv0 z`V-xR{5Rbc7;phL6}r4I6dSMJRn8)MaEZ!H1Q?M{0S`Y&0@+=SD3XFKCerdOOT65ZQnyv8?6`Qsnx|c#*xnW3k%L<27S7Etu>plAwyT zs+OjMJUXtX;7(u8)x}Qwm~zqit->Bg@B000&I2o{2G)@7!?`J;#aIzMA5X7R1KoE^ zyJw>d(VdiP_BTr02o*{l^DLcX=cd+BOXji&aleSx;o_C=u?4cT5EOj!J zh|?EH&u%KXS3GqsuQPrkh4V!l#I#REQJ!;rq&?`&#Cw$ugs4A)Z|B2fIml$3qML3K zY-q=?@hVb9@8Q9kVY~cmumc1d&|QcbKkBvtu7*}pY9zs;i7>nSb$1Hw<=8pXSXTpW zt;M9T#kAQ176Rc4Vmw96=N;q5G^!m^^8++*dNvi$q)`d>r)hUvgFzjcAE7QZL)bz$ zbWf5W_De6(hacY6?{Ld*Rq54d~>5M0ea@>jKe* z+msh>(b>0H3|NkZ9fpDh4!*>$x5oBI)lR6}+w$q=RVmSX-zsX++QdGfbGV$BQT|cZ z?C{|rw{)%G$uqTA5|YV7Nt$_%o-!SmeTI=sSKcn9*^!c;-OkCLPP3JXi^F?edtCQA zJbXs9F{ zpDUA1%=WHCN!69ztx7(g7tr~pV0DmPN*Jno2?J^|RK9AomQm?)f{jJS7(2g8nyEI_ z6@cYWJBT7}TXSnk`Pg2I+|sUSQ+=7bf^)GH4fth{O>I7ME|MvHl=}PR%Sz#kx-M3{ z%ShIY)etd@4CV8b&jdN!+C?($b+R{A851n}5Z+Jr$t)T=z?UHBEU@P4t1y8|T{vpZ zlZq>scRnnscxP<~N@SwnbxWGGWLt1a(`Iy%Ct1{1z9RX4Xgu8JNrlnCnvk;88}gV+ zn$!X>R4EJt8Sl@4PN*EVk1#Cuo@G-d8W2$dpSD?ktZ8qtb76n-a(_e17yjNB()71y z6^B>_%X-~81(t4ArpPUMGI80YEZ_`d$Ur}Q;lZCmZBM%F#dNtU;vZZrTMVigBg~@a zdz{M4TNIU>N$2Z>uRJpHVt`LyS!d>%>T{9TZbAj~YT955DC~x`nWrtbRlC*#o!Q8` z`g~PIfN8u~uyIWNwY3F4tPz%|tHF7lZ&{)k)*gp^(=cCX>R7JM8Ztbl>OR=h9{Z7< zst8_0e|%-qt}Ka#>&xt`+hMp@zD}hk6B>47eD55&j=5Q^h%S8+Re;EPl!OICMLc#S zeY{-1`Zz=Cbt*S1M^e*Ht-%)z=DFMXbm0{oRDOg7!`W3OQ2npPciTDbd0FdNZ;4yJ&aF(`Wra?Pc+b^Os* z!;~Cnn(IUFOQU9u1LlMSmUme+*(F{QfMGvnMjcC&@+ejwE=}HIl!soB_;~GyLZK6d zh~|UEL}w6lULr9XkmH{1=Vdlf^JJ(5JW2Bex_bxP*TIhQvMkN}knWsFixJ}0XiGe@ z4Mb(jviQROTzXZXO`c7D?iekv?vp*{-R_y3SN5<+MCxAcz^~1t!Kg2Woy5kAlVS7g zA<-%W%L8Uw))xbxYhNC2tEW;|_#+|M;l)7zgRA5GRmL`EFVFxx-Ry@?QSTOptaKmL z_I)v3C23~+VlPu4iSpC<9;1G;GuFdZGD6g_iB0Lzisjc{*E5_}HLzSh{Qa^-*fEQuTO^}9d&UV=IFt;{M6%2`hoIoPXf17gf$2I`h!BBVQu4)Tr&sN zhvt-=o;aj7GJSa-(rKQ_&BXZ6ChI-Bow|sGCw*KvlBb9Bzgom!Itpg_6u<)J(3PDQ zjx6TL=RLQLxF?*&|CL|gW5VLF55n;lA*^wRDJwX-awznD5 zw4;$g5M3}arhD@aer`ep9j|Z1aADSuM9q7Cikj!azaM-D83&!;90UfI>~4U9_IG+7 z0gu)A#kjbaA6NEUPtwR2Q>U-}KknWFE{-J&AB7Nthu|(j6KrsoK!Uq_2+rUzI01qs zxVsDlcX#(da3{FCd(a2DH@n&Fy}A2)_rLG$d%x+Psp+aZeY(z9r>efLu4aN(h6!Tw zz?+so38d>6EG-{i3lPoiY!RL2Ac5w2@@77KobTFra2%`EiLjp5eTZ~ zHt-0%UlfCokvcnoH4$o<{$}Z18wQ7qo1dSj2_=R;5~lscLCM=n@Vs|nhUE$f)GHXA z&}^xM4Y)c?^XfVw$u+?|wfr*u$v#;+O_PGRpQN-#1oSy^nvlyc;oSPOi?Xo$OMWwo zsOV^kJW+1cHbeG4Xf_E+v^M2TaZmA^{wPI@QmN9?kS0_p&*nZV0?uwx&lWjjr@+*H zD}n=eS-odO%P_!C{3FYt4klR>rMR~@gr#H5m+}UBvB^;=Pi;GK9-{S&t#19?1$&k| zNp$tWX7A!_@SQ`&F!`xVMP0NXm|ef$@3Yf3(4?Ur%xFL1f5fnSntjD*Xtr?I$nL23 z8cId#1iteaa${H_d-E8k@GvhQl?$`P4p(8aB4y~!i;pd@Vzv%XIC5Q|4w~hY4;qR; zr*WMYi5i@)Xu*c+S_=U-kb4Rgjie9dn-Q|Aj&#}R861wBD84?2$zCHVXYQqx8fAer zM1H>;F7-CY7>SqN3HSvhE0 zxYw6>3jsU(Q6DNSbgnYCim<0Cu!{YPNoK0c3^*?-0C&9XNL>4*>v9b*t-1AJm@pAZ z_^~f$V!F!b3yiU1kRx`ipQ8tR$n^kgkV=r0lfr?6PNzeuh@Utx>XVG`GV3s=a-atT zl{Ab8G>Efp(xgmgBPtm6Wh4+R(94&KGU#MOSRVb2lE3R?F0=7nJKhf??_Z_&uXpVV zKCfMpwpGMAnkm|BO{wcu(oa7dM8QnwS6wyHHxsNs zUuZu-SpOg%(lH$GR(}1lG8ZkteHh}P&tZ8rHLSPn76RU6%zP>U>)=z>-m@Ixm^{s z)Ym5;OsT%!=y$Ov6Q?=+xtI`xpAsymu`Ux##Zk#!A~wGE9O|fHhJ_P zH%Q)@FDf|$^B!B4e9m&*7Qv`rf(g59Kl~Dliv7{H(o4kd6Y4y2lYO>1bG_Jj%edv; zVBbEonWSe6aaLETZRg<|E3lhdnGL&5uKFuCWX&zKUes>p96dO~U7uQE*-fDKes6*+ z+wiu&pHfl%yS`#Ev6=?~b_s8mQDin`j5ynSE;Jhw$)rf^JofwAzeE_)G}K)?pc)CyAWCBsSKwCrH=SiRTC^mwZiwirujJ7t#4ny5Q0Ip zw*+nMDb(@V8WMTfHgZX+)>VAy?a6B}*VyUf)SW7H^5c6v^}2VV+kxL}wrNO1v18yzd(BW_2k}b#-s2*D0@4bo5 zGUn5EToc8p`w;HF-MA#v5W28{hjH-203xLEO^DuwZMIFm@l@+1r+B7FxbZk0Vvo!s z_Q;wcY1qucHDrDwrX-04y2h+Z@g+;USBbPa`g^Z=bJY0lRMV=aZ%-4CV`Pi0=M^$Jfqb zx<)7RK+l?JM7>z3s;?0&Ig#5l#}v)vj`;P~p! zipSR46q#O9bdbVXAJxfjr4b!7tigy>DtX{Ql=Dzvi#d!@KW%_PGHyn^>&0rKt@WFV zx;m3wlSFTiilws;8Ysc(%2m}xcU^M(j4!WgPezY26KRYTNd-9|(7MP*r7`BFj5*Ul zYND$`6$c-=M80|)a-cT=8Y@Q1H_T0!kF<@JAS*&UWsqgJR1|(*6*j;Bkz40fhTFK- zx(S>7EksEA+O?hAHSAclXW>p+{~x@$N7an9HK6SlqD78_<1YQ%q$R1L<-s!b%iPg= zT+gXztYU9$P(_4iiI3r3E?u6D+Hy%+w+tORzH%C&A&IoZ*Pw7Pb$=(kaFwgoZih=d z?zfv>GwRwYlR5d+NHw-7HG(uqi1Ttpse!b#e$=)LccJW4Lm+8+^`xk;e1KJFCsg{2 zN+%7c$N8DOMQ3dGRKceo?nd)Mo%~?Xc({A7-g(r;4?CB>ds}* zcve2bwXjg**f#FQtT;=t2;nP4L^%k@PY>ru(?;G5Gn)y`x;S5|arxjrqxGnUmlp1J znRbGIbAaK6TM$aI8aHZ_R#FR}hQa>yUB8Bv>_%Yfx%I&byRE_qc_6m>OMIHNVr=Nr zrVbO9as<15*&@c({Y^fj=VjOZ0CP})?ar(5)86@RXGl8pu!D4?Q!sh~6FAWX{@07nHBgW2>j+dP{o>;pK%}X51isHRW?R9pO zNmp-GUDEX~>lJhpa3>|DB`Xf7jO|^C<8Fx9>nzDE4xth-`yuF@kfkC+ZJl*7Kjcod z+m&{)EOw(PydiJ~3ljw@)-+bQ!Awk~Rag71EZa;v$gy*5s98A#jdfTcX}st#DDnFDbgV5uz#TNa<5hkk>^^kYFGfSvn}%_lU^yj-&w$Z>8lMU#hx%PC;Jmc_|{loy_gXdam z^_jC1>XIo&akkyBcShtE)jhni>?L!M+0SkvaP@m|ksAHzSU7A2P!TdB^SPsr5Z!$z zktGZp(+#@w`RzZNP%~}U*4L|!(V%sRaxdX4<<-nagBEwJHV1FmHnF<4OxmfM=pH4bq!z+`c@v;2;5^7!0w#IY4fg;pmc_dn5 zgaD$-PsN|K2zxrs=0axtf+A@lQC_s9+BtUj0YjD1=ez*?w>ex8jMh#^@*2iUlgpT( zMBC$BA8i#wU(ZOh#*SL2wc*K+!?ua6QypW{7vm2s8hNRf(Un@ictof$~JSC!Kiz-Hr z^@45|_tmD!D%s?iBG})!Dv<3za@>=dG_Ig`I62|?5U*#x9Kt%=qi*u%sDuAxv7&58 zTypqIAbNcEX}nxF{R@=N0D4l8;l$E|5@z4B^|D@&X!Qsxc@;y9Id_G=OMvtXMy5R_ z?E`}Jh#Pz`D-!~jo!=^b8cHp3kQMkbka>BaOj6cXVKnNH-JTn>8vzb`34(ze(dkkV zAy5u47*^DTtZ`##^ZiCDyz53VPQO%rX`J34xenvP{{t*}-j_KImCikr=YeSf9c>WS znOUp3f40o>pK~@WN`BAzshWadIWTxmb~--VlaEfnS6yy4AV!?mtsMIPSjc~Q&Qx}O z0eM-q-y+Nx8VLeCoMr-K=J1{~v@YiS8d2=p%4|xq5rw;}N}HUyOt0x8leb zMwOb}C1<5*LATaW6Slgk6zBL@bt*gO_z!5u>~FN={R5K9S3XW>*LI#iJs|miZ>8&h zo7woM@7A8)H@ph0F}$|Dd0%SF_Z43A7Gm7+uFn;y_^YR1sZKxKxw{#zn+DyxwBBk5 zcS1Nbuix?=eOm}(+am9ZBW-e{(X_Na&Lo$87bi6aG7A6X3?n>?fMl0FdC(LPwUY+* z`0@;q5CVUVJ+HmA+PSfWwya}~{B4L=gRpF6J}(dFg@&V&J*s|>uBn9eQqHwYcC?*6 ztK3&*yThrjfSpkIFdoNTxRlK>HUEg=g2@MrWKSw!Pd0{fUz%8PTaeL|Qd}&4`S6g{0SnfS?2OAd>1ESZopK9?UoIr({6Ei{R}ZHi$lK_`3gFGgu%KhCWz_|TMe$i6YR$9D5>^n>j!1QE!s zVXiOb&Io0NU!R=pUF^WzuRZ=RE6m=B{^x7@q`%_W{s+}|WP{C#dlthCpimq4rG2C7 z5qssbDZ&kNf02XqjVD{AW1RY1h$ds+<^{eB#MxVjc^0BK`$^Z2EZp{Sga02DoW-r` zrt1RAEJ&j6M#_({yPRPSQvlCNC_$quWxn5gI$X!EZ*MKuiXI>19v+}n-(KlWSskUD z_Zo^cnpoYYE34uE{cHG71oxw90f#p(B*C%V;puTAd5083_D=*s5x<^XtL#{~85PAE zhi{K7S-!;@ivSZD^Mu}E>FP+MAw7rRZlD~T_y~N!U^c*{AB?@V;kR1|cBtc`s3j=L zsHe@LZI)vb#vya8bw-7_aD7x{wpU=;UdRn+w~rit4+>l1<|c%HEQc>QHePk-R5*)R;3`GPb(bh z|GPfn2f>PoynOHzo0#J!xwBmSRG-nO-VkK6UsHp}%t>p<3U{^1+F9Ddo|3{q`(g8W8rcU4kb3RXFWvVh}_xpGsr%|`8gx|7QCNQw~^p1Ry>_-&YR z?kDu1$zqGEmms@S57>p0_q~05gjAYqjL?=SV&Zx6dT$(5}(5*Lggzu&kS) z6y}gzXX#QaUfckF2!}sRZ9d8QsJYdZMYZnb+e2gP?v*Zzlz0jQ`KFypn4p+F`Q}B# zOR^`gH%^sTzu3JbZ$bTBA2A=`zHW^DR@8;aM_El5y;3}ZI(q_AuBwUj9g^Y@i)fku zg1vchnY*eLF`4#zWC1GM2H&>~9kr)5vF~llQM5q|VqUx_ZBM z*Z1RSJjVUi$^?IR`!zZK{6LVb4;6b>mLg==26I3W_t=lhU1 zC0<)IY^zrv)=4c*6xK;E#h3}gT7%$VE^AX!xR!Gj)z$NUh-IQVC4 zK~#48F8K{<%u_Sw&n#BVirPX-J(Fsy4$6|GOsGD+M4iz}zn)ZW%?zUq2Z9o(UMTL0 zW^Qtl=cx&wX2iRlcI!vHB&ic(6Cx!INClI_KwQy(gJi%P(hT0@=qVA*ELJi}d*?ksiF|Lh_t;XRz$mnK7r ztGwz>n6GE=k&!ckGiPQU{4j)#{M6KOc{H_U;Y$a*X(3CTXbdPwrC4ep2l~9WOLyzp6I4I zVKb7RvHOQPNjqO`P5(ob#4V`S%Gi|2>Np8o3=33^#7A@?FC!7Gk<}4(GUyx86c&q%J8^qetpbesA-l3gj z7jjePOsaO-==vFv;@Ej8x}=WGuNGzf%UJbiChos=1%J`FQFQs6jl zZe0g9?ZRWMpn`TGtI0r+ptp^`nH)9FasKc%*aTSlBopUxZFL8=y!?>O4BfJNZ*o6t zjEq~`=jWO+E3S8A)Msnuh7KT+it3@ly|B*Bae6USF0&Q-q&edINd_h5$HhqIV-@ln zXV4;5<>6Ma{PWr7j%ORcJpuW@)6xlAeA&b-cHojLaK7tH58Y-f;UcH%= zhMAbi`+uXj|ScWw$=|{pynwzKP!+SO&Hbdi>HA>15qi?GAzYbB35J|*w z^bAPVRy+}YW_QSATv2GNPmo`p^LpC2B(Fj5uq>!J^b0!L#aKt8Z6>fL?DfVCsj~|+ zJxH(n>05irdSt7(p7MCH2Intw8)eR?HNfO(+R|=|`LC`U1R$vc)@CN==4?%{*~0cfLc++j~@uCSmJ-k?z;Q}`3|KwLW%M>4MbnZcz#GIEEcA!2UhwvDK*M~gY0s|=8sst|C*w| zet=aoD0snHeGaK?m?=-e9l} z7L3gBUJOfWH%ye58MpS-wfpqQ*=vI8%KepsES;*Jys4447lCfxrR&Bnpw@7~Y#L6< z$dLnohh-NZE$C><QaZE4-botkdks`grb^N zjO~%22NZ?z2T+czr7Kle1QAf6jzwE(I`)N$k}NU>FA(iKK5id8p)9*po6y8FH9vYN zSxH#^N!sb-{}y&sip#?;P7zdu^kQ28BMHjMGt)rK*OVoREEDsRw1P#Im)wCZ%k*T3 zddo+O$5YTlyiZ@J8RtWKsHQx8n~q}*GhDf#+JHAgcY<@WQD{yMmfnsJz|yfgb0GAb zP;d(DS!?1HVfy@1nyRwL5h|H?RJS9p{-hyWAE|z1Kp3e^B880#0VN^9mIr1*-CD$q z+hma|=7lPjDDVTm`Q(Sp1(h1i;w)r%2fu}aRmYS=MDtzMkXj5KxOFQz;7Yk0{6=@y z=cC}AGEbWTQP|InjIJ34n`}ku4*AQxBsJdiF(i}ZsS%1WUJ$IXpDHFYvsxrSag_+UaTaE6#r5#ARJ%x}RcyZ7>(PDNo8U z1_6^y4l!9T6>Fz>_oXn3!{~*%6}s}pm??(9v$HDp(LuuU4J1xG99gzzQf6u!=5(km zwt>2kkWldSoZ-p_2Rz%AXXAkwRbi(ilOhi)9z1y@%;Rv^1yQ8dlrqs|ylG(xXm?)u z>g_(wiXQ;FIueU3Z!t=hkj3`WxK3k-ad4@1TEqTSZhQ;TqR9|yu0NbdHll#2S?0zo zEJVsqyXV(G%rceFCsS2NP0&3;{$XUK{{l0h&^Ql|>75Qr6R!ZxE%KHtJ?*zxHtGiU!k zV*XzNqvqgE?{%^M>9$LBpEMf}>#`y5=%k5m2j*m2rJb}DZPej_OQh$gm0Jkd37&dE zovw$xR0kN{twg6*hqypA^Swmj-cQ)Q`s=gbRa?h-)pfMbN6NOG@nUxK%b!TrcMK)FpOtWW@I0#; zI39bytzz=PIsO&hfjFcOyH8D52Aj5p+o(q*)*&?F4d8a~U2jA+ zY;evrAQPH@PZQU{zHQR%k}kv?5%G(k5d|cHGg==X=NC4+BZpP&fPI$f8n-V6EdxO;e6%7o|$xsg1z!`Quun0MF)>y5?-_+qbf*>gsti zwJ!BCLYGZTA(mfRlE}*{d9nBFd!9Gosiuj>5LKzkzH=>iWuIK?cuiH|^9a1yXS5_S zU;3mDzE6|xNMYX;Q^_*ceA|Ldbper$PWW|0ox)^$(J*r%96z&<8eBSK#EOcCv!`S_88|J$@_83&hjqYbX-g}K|E*E(&yQyR?{HZ^FJ1iq6larJQpFlw zarX2jww@{k&pya+gN|D(%#)9VTX2~R>xAhB6K z%l;P`g1^0K-F|`BH`fE%SnF$>-G?l6jNzFWiRp>&1KivIIYw4^M%KIkasW97W_SkX z--E314BwBk!!xko2YGq_A%OJ<0Srv=3`{@8v;7#)0MEeiQ#||MRDhZB*9tH*{aOKL z=D(`|`(G%)@oNQG=>MhyEX==FfQ98R6kz?E3b4}uS^-vuUn{`+cR|Sd7a(N)3lOsY zT@bSUa0LpEmihoe2OD8|8*LkXcz`@Vv5mE@J}>Y0v`oKNmhDG#vN8T9Tka3_W@Gug zdUO0*7k2tz7aTjo-&BB|USNb4bYoMi#g*7oF+c(kQYTe(29)QOpxn1~tg{V@DJ-dX7Xc>n2hmzMSJ^1tnO4u*}9@mrYwTj+kjm-3-`^zP#eUEGE!F+;Z!Y=AGkyOse`~JpKa6bb|Mq?|L$^b9{@r z`>zQP5H#1d&;yzq-d(Uczc~o_kN@(vIyUzObzfQxKUk6Zk8HsIN>x(!CmRS@nCks( z0S1;ow*V944;El%{ceG~GWo5fScw0voWEJ-M+^O#eg0{u`_$h{|JyP6->mZ8PT#}# zWzBY9es}wQiT#%QK8EA2oWG@HV~78zRqyTcqYMW6KZM11v)&u)`|rIv-;e)hy6>TT zqu+<`)%?xy-_qZy!}QOXf0+0uAi~rC4300uzKA7uYg^_G4mulP#vCuqs(8`_#`TmKun z*#1Lwu`v7-U3Z1Xe&-mN>DhlMnjcZ}BgXEG0{>SS`@Y{B@Ow@CX1E`a_M=z$UdzAx zg?sb<<^$O8Lchnr|HBvD<@|=Vdwl+$>mP_@WcvVTb=`x*tFPp8mV% z`6Gw;qv!bH_YZaY_dGx5_|K}vA0CDO)0jWc`>$wW{54t_|Bs->%GSb0-x_FWWb*?~ z7}VO#d%?Dgpu)4(hab9d}yByRH%k{aqzzXVnA!1a^49{rT?W?z6%JeiO=XZfL51XM2FWjlP-EeT{+#NCH8i zyDR$!JYq)nyGWJa#V|87-buYfro6t*GXOt80Pqs<3Lpp&28aMe0TKX7fD}L)AOpB7 zWPk!d5ugN62B-j30s40p$L{XS!qysK$gOaW#9bATnl@~*Tj^Z+0LNZ;-* z0t9pb*Z^#dto8K)Hue?(+vnddTnK2Y&vfSjSby#?{?H)YrMWBm`@*o%f2DtCpZnp{ zkJf$(kkB_byt^u9CiXki|ITGNB)BL$D#(x5@S%XL6D)l~(~il31O?^ZIr%SlmhVjxG1*fzcgapfF9^6);&8Q(VzR|X!0a*O#I5}DqfN89oi}^DHik22 ztP>4qyK46Jwn~S>r(LsiXFGFem#%!63|0@Cb&4H|hi2jjisyZuf-NQa?&I)oJzIU^w6Yp(~`3&*V!B_u4tcc zVOUvbXaulf1n*EqVJ?g5a{yyY@DHA*JD63m%UPcrWss~H#i@{pqYA&bK)|x-SC}Un zZbM+wUwk>FAnH`Y&gA&kzbX+=$Ig$f{Z+f*-dj2i{3MFrNKwlexq}4-Ukz(^WvYG@ z>a=rwQMoW?;I>aMYAideq8}fssxdqN6NIr&yTX}LI+N@736jl#0DyV}31Z_{8Wh1gfgW-tlp`O4wzoQvDB?6^i#}^U4mv0(LSAS9R6O7I zHq=FOk}!u@6(JhR3KVLeoi;HK@g53?HhdDVd9>y>n?*oXMcXS9U)UlEG;q8OR@>u4 zDGmAq0z0xxlC*2twI%{sG5ODk;?h*G`1^afr@k|_=EzOs-#8zUS; zFv4D0*{;|yOU4;dt}?Er<7Xu@2<1hWE1({StcMWsw^0v3@8v)?ad-yy@_)m^6~nM~ zv9NS>Sywu*UfE6PWoZ_$t^8WHoc{w+{fnr)G=GS6CUy-ellod=8#qE85Zlx>1`;^a zsU$AE!gMC+bsXgt?B^a#R^@=G%+dom{ZXN0hz>^G*bT>Hgj?1x$k8>pvkgL4Y;J6C zUFTmJ1&Zg6USw-esHMa2caB)mXCPWkV`I0q`?~*D zrRzgs>p4R76y7EG1Atfx2UG_YR424?YK4gRYO3#ap+w^lW*@4#mX$2!dDZJ+2;K&&mc;4}zK%V{t#WpNmXL%uHrmpy@SXYuIai00)`U1g+@>L{R zW!!2&4EG~qC~tC(M;vj46Mf3N^w{>8^32<-P2?dC5Scztv{$U;QHm)ZK#L!8f6B?d zz~jTPYkE$aT-cV0bv)Dy!%xHVkZ-wnD&d`13-cj7O&OcQ7imaH`$bQ18B59=gMHCr zq0GR(WyitCal^*uOv+pCVh|;dO&u|z#m|n07ao2kH6zMuj?6AWnzGVAW;PVj(k=+B z_s2b-lFgx_3l4hL?7eYfEk_kbBWONA1K}#HKI~E(Ja>xL;}uAdnb2n!OzdzhxPr5~ z$CH<9sq^Fr3UMKuTRdtvr2fIfXGYy->@ZS}FjBQ=FOK`FL&tLG)h&7Z0)04{ZXZr} z_fekM6w5-|yfEpiB*^17<$LhV=3#q^%QF~n{s$=Z+tJdOu9vuL212NSX_bEN(P#}O z|JWN_SmmCy=3vJ&)XQ_uR>5S)Ffm#+@;R%f5f1$Z*+JI*-nb><%t_;U~n`q_KH^s&wKqG?IAXg zQ^?8QlQ(NGP`S+;naVKPa6;oWI@`g#(<^^;_I<7ppzpe2RLZs5hp-wAm>3sQ6Zc*p# ze8uYr5317C3DW7PY2?FE*fI3p~gYJpfcQC`~gz$Zup$QXN+* zh=EpR>z{>Np!15JM<-;DoU7a`DNEvgtd>pJSa>Pme7I%)F?zXgpC6^xX9NpJ4Bnk^ zod%lKZ)zg~OI6{c$tk%x@22#2AX?(2W<0#!$W6epCl`~Hn=}G2tX9qawT`o>a{j0q z92LK&Z~rSRr1u@TAhY$>1%LZj=QR{Whf9>hjT!a<9p_%d2K%=sa>sfCepecGj{G!$cir#OJ;801k zSgv`$$`0aY7Lt-$MFx^`ej`)$FZ%^QlUvF|B0m-5f;dU?*=0h+7ZP}1OZ`>`J zasBFspm$!m0qVes+0}N%w`hJ^<(pZQSiDWb};jEfwjP$x*}F`aKDTGt&9>tSAHT!ao9 zIBv6-WHhtBYzjxWjKUkxcu&aDQF z&`T56-u2U5z`#Qnx<_Ug3KJ_iki{Vl*ueWXs=`*&!x6sgqHmNt--bozc82Jk!L0zT zjJ@1~DA&2A*K?UdUTZw_Hd;Rltu%+)9CjzrPNB@nKYO^1n}n?27|@%S6l*;@r-Yo6 z>79k&|6D_`m8g|Jd-ekb%`xX9tdXZ4m-BIz zmDd8&m*n&kz41^apfjQ#DP{7FN=R~g$k?4nG;1KNiyg%v-H(*bqKSoBf~t{_r@T05 zJ%vjL&j>$Q@)2Sw!BC@@Lu0jQKfg6M%goG7EzRFWXMgEZdCCn>fGjTosvgAOQ)BLMyGC3vQ+lyksR~v3vTBaM7rBI1r zdFACRt(GZ+ZjT4v99;pjj>SFt9fxujN;n9oDM)WQKR<(lr}~m>w6_Oza}e!Jw2G5G zoU~RiDM5GK5Z*ePQp3dy)|Le-*)h5I7003gk{5}t`Q-u3bVI9sPu0fbZ&xR z8FJp7^tF==(wcZ?pP|aC8@J{+*OEgXP4js?_V6995!GQL`dI<>tq(1a&2C&^fBR_X z`%0gj(NV!s?@Y3*8?Q~%5RrNuyi$Yq3Oqi}ccY7_R5ZY6FiSIoDjTN@3@gupqlt>; zxWT&6EngQ=$dcCCSNUo`*-SIly}*0UzhF!58M2<`t)2dW889I6X>9<7V!F-cbx_%& zjQ1FH5W))#I%i~b28x^7WlDm>LnI>iCVI8OdE}L z6JwGJ^FdI_D@73b9D@!VopwyP*uoZ`#Dh z-!NPb_Vh!QUpa-vwk1z0St#mqD3x?gJh*n!?s;&%wA;!Rb@_A}Cbc-&(OdEBmy+cN zPKdtb6=J#NeY4MM9_6pF`eU&_A+GGnYlb*Bu2}vBPTm&qkK%r1(o;i5k&evVMK6p$011deH8&|8-zrM%k$RrEqR3 zSoD=P$ya}eYjni3M7;C!>60VFDM-bQA)rKhI|Z~-S8p%GOLi8COI%>=W4bNDUmfuK@Z1;c+~=3 zIXh`uax-%@_JTEQqE>Aps(Q>_B0F+&;4g{ioAo`dDcsFS`=L=Mcu^lSBvpXzYo(O5 zXIVYDB!(q1nHFT9lp-EFQVI8g-`e8aK{2qRb}SmACX84;eoJ=ldY#`6%&uuc)P8GV zpw@xg=CrZq*M%!@N!&d{&%M#0~D@v&*(#JezAIxXmh7(4oeh#OeE`hgiPgxO1G zgv#Als~kqngc5cXi|mTc?(&zlT#$A#SMh^b%4XAGbjMfgEGNhI7Z*jcacmQbsMNA) zVtOfU0c|Pd%z|uIRjXP6K~fUMB)JIE&pdC5kDk1j1#_iBPAN17*r9tF3<+9qsDDjD z)XXyHq^)r~oqoBGks(*gM`Vt#&8jWk09~-=SWu)zT+BPy#{23~6!h40)>3Vx*mtZY zd*Ox)PIg#mEzX292B`|vzJmLK4C7|&kylMB<~<&bZ}D4rn)BWza_{r+zF7nU?Q`rS z_eP@MW|81o6ovXH`0H&8^dWyuj3ZPPu5d&4$$Vlm3KBnzlxmdd3@nJo;#?olh@@g$ zQMeJ_$9VRxbU|FVuWO)%dj{$RUg?rx{gTRu<6*o5Utwc8{gKb>#OE}{8lUPfN2Dzo zS%>kNGwB&E1ko2iH2Psel)V!uo$Rgq1JwSxe2yEpLF@H{(%^`PwXRYq1c>mi-T z51|_jwJ3`ZJ&H+bCLnYjM@da1L@~|uVOrs75p~L2l8K*fFA?;ccXftz2Y-%R`NXLf zH|gCBPgFV!b9O1RxBNlgE8LT6E`bwHB60CKz&=vl6eCh;{7bfcp_*xwwYZ>n`t)Wj zXCUzn9wRL^|G&@qU|{)AxvXE_@%hGN(chC%ti&Ab48*J)jNf^zA80HN#($x)?*INk zW3m1jjm6CNM>N(SFjqpqb5~-2!d__ubO5>lT?R0<6E$U}nJIPWUH;7{Cr- z4{!iD{wp!Y_A@cY_J4;MV`ZfOkr+!lH;-Hcv&j`_xmfP}>FSj!`F>5a$ z)0CCfP|*{GH6eyXrT2Q$vid3P$=EwnIFIf4nQtUo)f5GCIH}}f$u4&m+Y9N)ZfV1x zD;VQc%XQ2>58nz~K8Sm!SSN%TMWtRUQt_ObTPS_B?Nyh+5~*H1rkN($RK`#ka;hG0 zj)Q891`cj+NH)5z^7d@G`5N7qi^M7W%bmDJkqSyNFglT#M?`l^hg$5p?V=l84}}1dOrp|Qm&v17W^{) z#eD;NU6_cGkFLgN?#%(l$IgNbi`6kg0q0m*g22;FrZGJR<0^4afJ7Zafn42ZGEBi+ z3e&l*r$81@8gznGH||nA=@5!07lt^D{1)jIhLBhGU#Oi`2iwl39@9nCfE+jS6D)F@ z;Ev|WW7b;8U*urx0k}JKXbxk&4HwrM!AM}@n^gu8Rc?TK02UC+?i|?PqTz7VxgRNB zesj(ebu4CYtS47H&zuLsQAHrJN*J~<2{34sLQO(R%oo5LjOsgII0tQ14xAx+X?erZ z+Zquo@-{v0#7pH=W|X2QgFOk2jpdB+MQj(<=fc12Mkanl)O2(}g74S*h7Jsc@}hAZ zj&3fzvwuMbhK8?SvOy%yA)5I>asL3ltIDYp)zfBle4-t|2o$EFuCWKzIqJVX5;_8+ zN9l8h2*!;oNLx^g<-TOYb_n9dn9#$1g(z`#&TuYLEM0>wE&p{VAjo2Surx$GHEd|p zPfUop_G3YDO0)AsF@dw#Cj*6Z) z8YV5|r6@7Ko4PG0Uk`DS2{WGAbDowRXGvGrG>S9!)*ly)(Jjl&1*fPC7!8@ zL&QCU+v)rI6h^~~BW?D~u_qW_Q)rW>-hspu^4rZa67%&KNRL!?Owo zQ-V8EhEm^Y2}7q!U9>Nbz}tY`Z7x1snG0fw4#5SFv?$OhP^~@X6%Ng-E!p12iXM*0 zH}$OH{%DM_)F(Q`RW&{dE!+roiidS>@uqz}>aFGL+Y8J{G+X+e-ac@uWJkoKir4A| zr9@=WeWI8KTcsexXLzyj$f`P@!~MdalsYVprQ=G$FWxk)QRz_YMZy^r{opa zR&()42l*Orz?i46C;&a;eMr{O*G_T^jjM${KRUV*Sd58IL=?@+-wW95qTP0 z3i(LLD&#$HxO%AjW5z0fOj}`LlfZ*n?TeaHx$_5?!1WuNc;8GA!u4V7yUW(ZQA4`o z_;twI)N>~|KH^Re5*zrYNWC^VQ6XyD8Y*V)s6k7YlSC5KvtZ*3JE{5`!>ny_NiBUs zf4V|4Zv;!&Dh2b@33n~xn9f3aQY6MzLdML3_V~J}mp;|3bAEZKdH`xGOv2~K*7GDt zGcks}rE%~G?^hK+xa0BejFNegC*;`;7?{w8h4^b35y9Cxp+kD&INYESl4)7Tp*)X` zqcpyF{aTYVHf|7ftdz*f{|xRB{480;^ZNb~ zVF;4iqo>?}71og0tdhC%Cr+{fANWw|F&ir1@AlF53y3~zP4>|&&{)TSCfSh$F;PV( zZ!(HYqbxN&LYj$Jx2&>DRa`44EF95b8jUvr<&fo^1)61r;g_;th3gt4%|ys2xY&@M z2S}Y-!)kMCTtjNvnxVJ&PbX}e$LDvoWX8Ih9nqQ##eWFz4B#p{S9KVZAL-wKX}h@S z>8Y!$Yvm9LGp`sG`RI3JvqEq8set;d0N&Q<;xdkaK#?Qzz44erlrUA#2vPoS&9=lu zN5RK~w9Y1lYEE`KRbPP^GfK}wO-@z&Rc`f$N`8A>q~x(puP0WB9r@`7Q9cf_R!~r#LWn62Vp~xIZ7#lfG`ogTDB{DKzNeNi zDZh+1bZk2i>b*hU8MH0=$yo{$Gjc*qEZE|}IDl^WBVt4-m>|Bt7T&{~)x2-2Xtwz! zcGMxGs}~l(T|3*v$~zKTfo1{d+0>8Habl8QvBE^k18!B8jCorFIAoAr(ZSjc=>6gt zx~%5Is{>wR@-zy=EKs(iJ3iGzHQEwu9q5K$)=u0DhIHC(P-Tk_+7X3xN;qg46Om$V z26zBg4Vu7RB}G>yiGc&pI9I?~XTJamV@my_C0q}aUAo{W_)b=o-2E$@+&S8QnOX7T z7xsC}@e-RS6LTiCrlVj%*e_&RIVmHmDw_KydFUU}j!XpLl%yQfcSWb7vBSN{GHBGF z3kX6B4m}WehsIz^@xqkUj39X`OE`k%Qk$U_aCdhLFatBp;0_4{cXxMp36>BXg1ZDuaCZ+HBzPc5 z(BN(%@F1U@bHaDuz3ct=pS9Aft9Dga?ds~5I&+~Md?g2zHhXS&C)wr@!Z`I zR6X4-R9Vkt6}7NEfHnv%VN9}AGFX54<{OXYyRp)f@XVqO?W^Eb3ELxh4)n+T0>-3I zAX^Qp86<&kP~*Gj9P1pyLt0~$Ea`n8+vQ_qguh3pHUt_ZqmIP933p$AB_KCkqn1fT z?d@Lq*`h(Q^R?=7@?xlhtEpzlORO3O3#IV>1+R%VIIP!Ex~&rn#W89Tb5sJey@B&z zgcD=PjJk1i^Y@diltxogTg6r=>L*K~imV?*!BSLKMPG^SiMtn#6uqck5+B$(a(&HrP0h9lg_v_W93sVLROV0(70aiWPcisri(HPNM z^{`TTmHI>?oOP@+S78Q)wYDSQGfY0*E@3_j-F9JhS=>oP$tC-wR~y36OGuP5cUsT( zkRfR!o?JU9zYg1v1hqo#<;&-QW#WuCH0snfK|&d1L2xAjT9hqM_Sn*berS7pNZ!6D zfdx?^Syz504be4l4bkqV-3|O0o<%AGSAy=TV;}+FINTmFf{^IX>(g4Cz5T3#n}$Jf zF0DW1q#?Plubaz)r!jrl)^%R8#Z59@-=_#-H{cnT-JB?Vitx0(y={(XD9mcF$%NUh|t-o|@lybMv9-E|pva7BI$q ztG@XbRhyC4WsBXK&1xYqH9yM0@8JG~yM)Xo7Dp!H=O*daAT;07bT7S24n;h!XbUqQ zJWnF0(dZzoY~q|N^(CtajB1g{5HzUp2$?t5lQk5JA7l#@f8Uic>i~J9e||dhs?8)3 z@lD`0j*l+7CFuutCOcbWgPMcg{A%;>-g|V1)H<{dACwB=igfgRRp$6X$}D=cKTTLy z8&1~iE9{pwkrpNKiFU44)d975dkW@mkIP42{`8P#?H4f^GVi}_#N`6TMqmPO4d_-A z=Wn>6U8%a5v9>lL@fkT@G*m$hiZLB28liz%z1xl@Rh6@|j@6AA>H7X>4R0WEY{kKD zj>RYDyXq*@#->+C0M8SQfR`Jy_B)r%7a8ToK< zC&`Gn4Lp8Pn37cW=PQ0YL|DB9$DuT6tS&cJXnd6v9To z7+0y#kT8!}0WxK`xsJCpM%*$3dh1&q{OoZ29%}IBh9mswOlm6oJGtROhl2r$koaAYRSjf`|8W3SDYh;-*Qn{`CpR#o0nUC!u> zZz|;;_vxE(Z??yhvJe{zJ%jMHejJ%7l;)662!g;BcdZ=f@$ysKBj2F1cYXDfw+~3U z@o`PZFCog+&(yIqsN<$eG@wVxjOai0(JiIG5&@_Y_JItJzT0h`>!EYMYc6dHw9P)> zLg0}*C;y4*)75T6tW#RtDnXb`k%0A)s=k9A{W@HXfV5cL2lX6te_}MKL=Y4FN&Zzc59Wsyz46uuONyd_&fQHOE|Y2JB={MG7BlTuN!HjsLuK z$#<05K+$#Q@I`ELP?mLRjS!qwRNxtMb9yF2F~Y_Wd<2MCtGpc?!^T>PhlfYb>Xe{N{ZS)> zl#vW?+&r1)w~gEK9zDio-@a+*(RoDQM6{RGz;3iHagosRSChK)E%OAkiK}8 zmpO|lpgqrzu^G_tUTBj^bBJlVoG^U?quVVX`kA>iN_)G+MmRAUac+3{P@~4KR!}Q* z>{!-o1rV#fi?&#)P^68?Ad|b_TUX#B4$Ntux}fPm%+O%L_)EQT)ug$Sozm`zD)_!{->!&K_L2Jcf z&n^n>Og#SAAlOQWk(aX~j#J{{Ya(L^(OpDpj%ri9d0*y5Fg@(!d`G+%H)E!|#p3(| zZ?9__1ib({NAfPV3}5O|4E$_YPNJMjBR~AXCi;t~eR1k?Ti3 zp{45V3F_8U#ow5_=gm)g*`pF)ZwHvcYg6}|I)?%tzt>6c{9+Y(bsS{g72Lh#+ThEN zuQ%5hjvr;3^oGGd$(XtaTNnSjL4AfzB9p9{+G{^Gvenl)!lV8OHY1?LugP|*Sm4&~ z=S+Gdt!PdPR!#T&lcQ*}b??RuLiz8B6oDktdl$mtuvM`+qJ(3J(ue`WdhVu$@2xgP zw9462`5Wb%sd%g*EJw5W9(&7|M^mkXikKf9y0a#ODqnFg;%<&3@5R~k3GcuT#Dsn$ zR|ylzDC9{}tZ29a*N$p`sG{Zk*@>Q{=86vn$X}ia%2^lb4d5rSYDyz>k0HknY_C3c z@J2YGyBSqGK)PrYI{fjC%EL}SnveQIDA90JS?>Hf{z4{{cAqMLK=Joa~%p$*b88WZek6;&^URv&*vDfVjj$(Ut z8VbX!))rH*y1Bf$9pn@{gIcA)#$eUYlm`C3c*bD)gWfUV*6vuUEc! zbg4c=C5g#NJ~33X&%g$bAT6J6Mb3TL><3DQkdqDbr!jm2ugCDGsBf%hWaLJchHdj6 z22I`+#UOL>X;Zwt{Ve#wJs${2#q?%tm^S<%)`H6C{UYor#abg&(K|z8IT@iRDLpVJ zlb6At;JE_$c1L}*A_*q!RL|0qqwlsvBaf*Zo3Mj&wNZ#-R>8lcA!&J^t_J_)SSjxU zLuqyR=jn74ydJ7=n?J+6Ka~Bl9GQt|D3T!S9S?u6HI7TV?UpTODNmL%6HkwleeW`ca-Ig*ZG6fzHUh9^b6|+){() z^FjF0yXn`sZt8;0PP}LF@2a!fHRZL9tD0oq72d)G))i#@L(=GfS^)ju?&bKi0{T94 z1cd&vg@y|X{fE>M6#5^jBj|rrKm(!wRq6-~`2UbPQg~4M{C`Uznb;T`IGO*MNBWgW z`ZJeg{SWCR%fAy!widP~|H>*EIGWg6o0vNP(fcEf^jE6sze+aUb$+q@1^mJFKgdHl zS>G%CkJ%`8Pj*ieN4x(_NpLaNRk87kJeM){U5$o>fPN)kHdOW*6`MwSXhBWEKh-KPc333 z)y1T&?Q?#0w%KEm28kO^IXpqtZaeb~)7$E-bdJo{SZ2S0eO`_Lj(0V}4T zZ7`9|#}DhK>LZ7O9lHjHoXiw4xMQ~ z=)R@yrRdf2Zd!upguZh2=H}{!Kk=FZ#o2UY3@#w*xD82^uYYQZwQBYF&V8$6*m*Xe zT+QO)Hh@^@y*Z3L4dtyLs=jW)V~N-=)BO1{ zrDhwI?ij)<-}YXk+Pz;faT@6x+P6m)A?|VZG*j44NN(R)I|JQQ4`|o1bi2JfQ`Lno zF!wPLLxY3ZE8-7mYO%te_!;t6Bt4;Y#gu-X-mPdzP!T>O^OQk=a)IUyljU_ww^V1m zd*+Pf2kJAN_ehe|QA^mINGVC;&z>*@NFE>|8geba7@}gNe&Zf&PeqUA(5);Y_JSrK zrwp4@Jx)C?6wX~KG*pcC5T3=Rvl;0*POB4i^_tBwTLy^h(3b-}#mXOLm(wC%LaVGUjemtnUuR-Y2N zcI-`fNU(xP@F@L`Q??FU+XB*Denb!)$;q~fs+2m7K$Z2XL3$(TNPyYc_JEcYm#26> zY(aGZ*6~tt(~bs?cAY+MSkV|Cy;E&wbl|&=IW`IQ%Ww>kriy7K2MZ@Vth^!zV!~&} zK)B~K-5DQOVOds;RrTzzSBd6thC=6t@;+6@-iS-#5a#F;U;2#pu)eJL?&XG*5v>ty zy+?Li%^0tS5HE|rErl}hXwvxYC5i$J5}&f;BB>MtO-Wvvt|=@TE}yJps$5zzu!b9B zvd5QF%z)NjCGW>_Q(wi71pOCv8eJ$j(@^7kjKL~AiN}FW{l>=?=5ZJP#SoCG225*3DaCghk)(19!(+VlK+CJUe> zr=a~=B8gUTxxY6ILKUxZVl1(!KTAAv*%*m;06x+}utl0>;21OEl0Adak!8Ch)q;Qv zPE~X0cz&dE&e~8ud;p zWS&;_=MX5YCe%VX&BA?)C(kuOPbasgvD%h3osDz!ExUwPJzJIiQ%8edZOkCb8vQ|Z zfBxWrKe1P$2e_+YAE_<^KCXex= z!|ed?V(K7yBAQ&-DqO{SPIS@{1c*-`7|Sv)UpSB~|8VE24()$>Hh zABu|{;0;1V5IP$Plq*BFACuRHKQT99e82u?CD078)_{}vDh$#5Vk@$2;Sg2o1Ra}? zx`uF%y;+F{Pxrerg2hw7Bbuy8l8IMAxiPfRLd6D)BIhKX=eBI}Z(m|C)rVV0l`5UX zAj@9i%LdsYsfB#*>+n0S6(uKQg-w!kG^^F#A#4_`Mp9TgO>pJNoHIC^lMaE?kkw9% zVLd=0_9i=@+3qameLeY77Y?_0&7LK1HSTHdy4y1wC1x&@l}gvxXjnhnCfCD{Yr|#j zD99C+=Kl0#IyGmQJrQ`9jVx-=SB${IBr zvl;nle1PXI9GFKM%)=>8ToMjnLD{OTh&P_*2{+%p26ekVw(8AsTlvyeakjM|{E;o~ ze1zRVyaWdle@Ske)k7*MM*3XD4wg9s=aI+>aiD6Z*<&tb*!rYvTy?zlNoCfzbWXTd z9Jp2vCiq=qvPupPxsQ09C`l&zm=hFE)3h(>y{bdISfgXlYfRy11XQbc9WPb2LHTiM z2$^s!*J}kBFCsC3YYiRj$-&NAmMY5Sj2=yGOIjQx``!g|QbCAgIPsGnsn`uY z!KNldx~{A|V+M|yX!PqeILRk+&UXo0JU`JmuwRf6D>XsyG*^IpU>U^gzEkD zYNUhe5aeev72M*ljaM+P=_7(010TOvS<#v^rGad%;oCFRF_j@xJi;mwX`9!p-06Sg*n%*uE1IH8qZ_QBjBGmI@cJI>vpi)n9!4w{^1#cc6U zLEVe!JT*$%2l`(+%`nUAX3(=x98>C{OavF_OvD=dU}sIaU)h{mqy3!MgOYw_D|!Z7 zah*k2u|M2bn%EzJT0JoYe7l7rlZEy(GG; zzS*AeFi>wSzK}LzX9T>K!cmg)&DcIjWIqo0W2G)z<(Lw2@3!@O>PxDQ_R*S;b4%2O zv96NUuLoDQ&sS_mg0OaQBUMxA<$AtmWJ`0B)*>X3evF3(C0mg5RAxCGi$j)6(gj00 zke0apIlp*)VImX@7^FY8#{#2~D`lGGSBq$NUTr4BS+_iA8BoOL05SPfuvyi!1$}L+ zZAD|M1j!|`juuyeG*ax#3J)G9GfTgR*NoPRE*Q)m&OT04VU-M#bDK=JA+a-pf*$eO zd}wP9A^^I1>I=_le*hSHngI6p;^X-_^ga3L=_pL%i`u!6FSEju5N~_%cwtqG;z@R% zK+k%a4;Y(Yqu)3LSC8M6f9@Qrgf93XxEVf?at0no_LK;7jTc;jtitd=3n4<(Ql z=5H1$VUteONK;MIKz;MF!+JM}bJ<7tc-K%gY&g=@gW$N$!G2DU2apDw+=_|Kv~=LE zQ_Q7WH88OZ(AHASq?4~Rd&{72`TTh##$E(TNcW_deMt23679f12ELLzLvJA2EGPbs zGm!`1dk{(gaYgdG3N(O9Jv zHDsyFtS`!r+EM#6tTa}~QWN0TQKFyioIUY0)KdIB5>%G4kf@aa}RP*1`(2& zRi>`i6zND7pTX&2QW7vQzYo0wElo7_AOJ3a9HC-1MH#;5G?pQh zQz@OMr}sy&=e%|cnf=xyuq~b1N{ehK0tf!H0VBlG7n_4WP-QE?wQuY24@%4%!mayR zCSkednU%1Os%i#6!D6~SIOp%k5KZ-gB$~+f{UXK^mGEy_BFV1EKdn)rYvQ;mr{kp$ zCU(?)$WzxaX5&)-q|(V?e+B6iFJtZg8k(-HD(jr_RrA}Kxe2}B6E!VF+7G-VS*y~B z^w{g8_E-7)8@p~%2Z>LXOkNyyR9*~;BDXTer3>Q|Y`%n%=a-Nvx35kM|H*fS)8~c6 z&<=s$hd0E-m}y#HTK?h*^OU+t&Na=)+Y>J3tSQZfv+YaK*HDs?>qm8;L({^aiC6N` zaLhgR84Wp;~gqKP&9Cm3N7SlK{y~Owy7a-OVf5?q-5n0+w_6jGN{W? zUG*DojxL&5@UWQ|y|=V&k&yYZJ+Vj>1a4P047o;&>zktfV7r3qF>T$d7ru=xloK>2 z^7ihD5!3ee*rHa$!tR^fGk_YKPDxK%VfA}MPu7cg!}S<>LC;v5Wg(hlEUyU+=>o+H z-!$^CLMWU~!9C3w>EA&uU*uA=pKT0|=Ym?*pFSp4?|Q1QHO6ktmeO6iN+?*XS*AZu zzeG8=30oVU%!80!MK~On`cY_g=7LlT@QInwghEF)e{JKXwvf27VWml_5hZ+{Wbt|a zF=ts-!3;~iwbnMc{ypfpCgb;phse*D@wVpX*zyL zVQv7z?&OY6uQGmmHftXDb{ykrGXJZ>F`wH?cc*8jf^53*N`o+JQoJ^%(naEn?>f%yboO@f>kO8Aq-AAQMWJghbD>rYWIK|3Yki|yCh!#^mr9*?d9>8d!6 zH4W@>w&iAa93|DACFQ$drUMUO;XFoq#YuBCtzcy+AYKR6e=pVWN#IjTiTa+h$r22_ zU57=9InNnlq7ADK*tDilQJ&oHv+|?j(!0M$+}^8=!^zE&{bXl1_?VPy)|iY-eA3_a zEmagj6~x-fq#B;uI;42INGqt+!eljnQZn7Y^9A`l8qEXm5^V_x)%&97_70EWkpApk z^NI{2C?>TEAKVXXPT$}}f)*mN>AgETU(q4qjO441k=qoOLYgXo?NfV$eBv`Pv)ZjA z3>ZU=+FN)g<^O^KnD_SJoAgRpIXT-xrA?8Q(ab0Flt!o|;LS+eUr zigyuLa=Xla@S$HVcdUf8Rt1zA;gw{eX!B0giND%3BtMt#EC7tD3y>(+)IbslkI^o9 z^anXN2m)nCjrgZ#ri^V63xu6qOPb?}Nl)K>g#=UA`ZsBvW_TS7m2}LzY0e~^hPpnH zU#w=L4zlZ%vyf9T&hnSWK@70FW}JvgO#Olw1sVQyFV)%ZX#1;E^7TAlK~#?+mYfr6=J@ zpsRWt@}Z@pFit4m$uXu7of!D!I&9vNrVu2hVbhdjh#LV?O>{yto6-6xeOv6*^20)7pII2&r^gaqFL zbA}XuNJS5gWz*?e6Rk@tWjC}xxo|P+ibsvAwVagwafz9T2;tNlm0_x(c5tjzS5Eyr zp{+C?F6@i0)c1^id(VmScJie{=PBr7Xq)HTSFaVtgGcp3I-A?gt~qkVV{A}-qvwon zU2q1-;f4i{j*7|y&OcVOne$yl_9us z53et6*BQ0vPw6rDtF;`HI$6D*p3Z3<@RmJ>lQeEwb>=f>XN5oO-ABj=oHc!^Z$ zHH7UMffb5CAigk#uG7lb)M2IDuuporcN z^iIfQ;jf{*&4=_WABt)f#r^F;@sAOmoa$!H%!A|K;s)Uw4qI)As$n-~!8N9J&Ub3- zu(gSmj0adt<&H7KD-!jxk;4tWjyRo@zMxQtYv~2a-~B~xHK^3ihdlW$qz`%Ubr{AB zNfVJZ;*HB8!?%wMONQmXop44>Y(2Uy#khgtm*fm?0R9&(ID@`G4OM;S_Qpj`W!qmbikw=5H8;~?Go{hHF_QKEXKyGk zNHLP;1!FjivT}f}0H0Ln^K3P)#vk*ARXZT0FwU@GY|*Q?{~kP1RD<@?6l3U}o}QYEyRd)|n&DK(Ul`N@miC z=Qi4i2IF@Tk+sr|v?hT|oUl&F`EA)}3{AIM;1S~EE_Z)yV6>#^mM@bR9-}b-UUOp>p-S&M#e(b05 zV^gLqkcnzJAc;}q#nsuCweE-3!)X#-?*>@or+?gVlNt zLFXAkU!A_Onbe8`(T0uFaLM8(p2-N;@-l4mc6e-kUkH=F4)|q>t=o8k6~@6BL6#1_?os;&>z zJBv0tRldj|p3OWO%Vj`oVF+gMA_?hW<$bPP(CIQwy{J86m6#nk zqK9Nvs|dYm7Hcn&>`r+*qf@o$ zQHfHy{8kcjOFM%rz0d9KK0?2^%w9Tuf|iM^jdXRPuk-j|b&#kz?bSuOq&nBaNSgMW z?Iv%i;la0^Wth)@&aq_9ak^=k<^?w1SB_cb-ddB3KWblUk6$?!2qyXtXkfH}zHa;}d^rl}4e zo8W4|YXm7WN2RX=z9ls)?qEsm7=CUydy!l>xD0mlE)q(?J&%-lhs6-gLj9FjT zA@gs7KBf?4CB^ImND>Aa>0#A??YyYG^$l4Blfu|7x~^N~xn9S?8?y_eG93HFo0To- zhYcgj#b7M9E6Jc~Dc&24Pv#EYe!(9|s#YM3Z_BTGwTv-xv$W!Du)ch__Aa4hVPCw_ z&#$e|D=Av>E|52xBlB?=gtnjCVDOIVs(ESqd#(C83r6Cz%8*^^cJiFg!{~~ze0QOE zGq*xP`&E(uahtzjs-R8tlyk|um4)*Bv^qLUHYz^*A8-0R9<{(?);V<~+MObR^3ozI z>Ri|Ll3wEX&Y5|)SzZrT*rnG?Cat}oLu#vE~wXIq3*Q_*J+=_nl)<|UUy$c?m z3x3ISRjSoidCkfQx+*P1t&q~Rqgk@T1F0kI*XL3{CvPr=uaRYEOWtG*#|09=lq=Vv zC-Vxi2j@r8kFtiI=G3p|5h}-3<}c1!P#@^V2(Z-M)f;f7|boewnVRG=5)`j z=aS&EDV@`)MH+&$V^;0mCusU8ZtVmyJ=n{%wAdtV{vqDvGmy2@l^5^PgcdSYV`@c+)iGg4fGa%qxUb&a{R9Z(kamjyQ6~{fdNLE))Tk2BBG0U)SBLJ~TgT%=YUGDF*M9%aUglRB8 z@yK?&2pTEjmy|6H$Rj!fv{g${uTW5fV;Hi!j?EY_NrDX;y@8RTOZjaE0V8~Qcw@6z zmxzq3rjjtw>{~lVMrn2xlB$ZLT@v1HC@HlZHcFn0Bx{B~j=fy?!4E$gSaKoA^K!gG zH_P6#dIF2^Gn|-Id(F8vUM!-9pL)W4_{SteIy^L7EF8V*B73(yrn#MORg2ycc5Lcg zEe70VQv9^bTHMIQBBL4_U)ypzjSayZzh(UXYW3DF@L4foCiA9BPlb#pw+5g;+j{)1 zTKn7ngn)nmkz8Fpc?|&6L`q3RCcacit&sh5a{ddt*SB!1Tj}2aP#3}dKdg)RFAf#_ zYZomL0-^*#p_E(@;9sQ>kbjjzK!E>I3UPl<+~1`Tcbxy_VQ}1cL%9A~262A^AG?f! z`@ci~UMBGi^Y=k?qQvZBJ_AVEx;&e1|KkNWe`IrbhJN&8&A5$CptCL)P_IXoio z$~QGcd`A{N@vkWI11$Je%u&h?c_O4VZw7F8Bi{CediPiy8iqb&ic0K$^X=OjwMC;? zUbIx)YRJPtNcz`=6OhKZ&vPu2!ceD8uey!sSpSAnl&yDML-9XBF(^`7D7w1!+tn z*otQp+Lq*NvY!e_i{K~lxA3+wYm$|N2}|>^i|Dr+KT)Telhk~A`)Qn8dcA)5du6&+ zQ%~(o?bkD{rgyG*u5Rvw?!4~w3m7K?jW2KPS{d4ckW9ZM6Pyk1TJ3o4_+@Sb)VS+> zZO{3dJgz+Sc)VB3Czl(#1lO(Br$4m`-V*e>M8-toMeauG@!XWRo4)J{fZ&7dnI&aa zvJLjfreiQL$ny4=b(#@D0{km|gYPnjT0a>=u0}R-qmsVroIFwatp7Rly+v^;+CVjq+Ev<~v#b8E&fwXSQ8=8@_f`T*dXs+H z-($fupNO=k2qF#+SFM@$DbH_od}~W7&!GT!e+fuE=NI8Yq*Cnn1g?Fdw@fG7pEg>X zKo`7O5E$<6pX)rN3)r?#U_XA!{29I%ETAIyP2GIg)1Bg=*?c7WA_=#G2Z4|xrJIOB zy`_8wf4&=MlaaYCVo-s$(QRDO-)vR6Y8fLY4MU=&A2j1vEW844z z%nR0HaJdm~310WGzsY$K`Sn~i_!};*L)Bk z8Vf$U9d3cQIMWUKraSvDHPtEM6IgM<_u@%?j-F_Idki$+C}s4HvLE$&0aH zV{*RFi4>?+o6fE6mdA5WstowL{&AUi-Q1+6s#PdA1h#M7%9$7?p)b>GXx*^$F^T5N zh?nd}13`Ttub4$wN@SY!)JpvxKJHaGC(yhH=S^;AS(7 zV+jl6uz?gih^*>@(--j#_dy@U>$-2BV4n&tnmf~)wBX?4;TKCkWm3hi+c)d-aC=6B z;TwVI;bwuOIr&<3G6x(^P=Ydq5!zwGGHN9JcsEk;Ttv_EO-B}s!)Ls$FqNJJOu2d! zYcqAX{e#)#C1>#-1=Wi}KMm)D|Q zA@-Au&ybCX?(sp0OS+`4VFW(@h?O`Vm956yr%jweTgzHwoct^@ZKhhquB!J9qH7mH z7^?$cK#}45QhO|9GHU8_Uk*9ui2@S^a!sR1psJR!JOQw6xoRhvfr+-*+(yd%^Khk| z>=P9^gCngr?5gUY5HL3OY*QNWjInlw!qL?yOgvondL3tHoM#H=0zuruRKAaKrNY zA+h4GLCBqiOAv#PAiK>c=ykKbnqF4m6>#JtB5He66wCLXH`6O!1)bFT7~ZsNuBigi z^~c=Q{>RcQQHfj#yCOB^@_tm zHwy_Iw^d(^d4j$f|hM3cPUoMzcot;Cys=pEIj`bsc zPEg5Di5wmv2Z$!-sOF3?IKD08w;A2c_7RDmAyA~yU+b+`;Umv7t$uXTGFq}*)G%d9 z{A$jg<$H*q)r%5!5}8QIbgH=1cY5=nk2?$DU(8y9znvvu$q^PKSgHRu5 zq4k*KZDQnfWWBq@GjnF zcdE~$zLPIznoJ`m2>RX?)k`m(+7pl8XBs$T=@QteG@kwaGZD)0MtZz3PhMs;gDIWy z$HF)&G(%?x6G>)Al5FfRGH5bu_$@nqHYm(qlaGU4=srQpQ zOA2pN$!+rxf3C8rpC~Zd38Ja%H~UdoPSnu5!q# zR?Zt7R=vXPRH&&Pt;ln1uD5ghFeo;Jqi!l?F|wRKA{&bd_oXI^mN@CqT2UEj$I|yE^OPs8rH~fzI3s@?EEZ;Z zERjniLpB|9q)-|kYfQtYjfXrQ)9MKOMKeC}tUcR^nU1@})hue}hTMMo*Xp-V-K0Ec zclg-%XtpgA`DhIFk{HZ}@TVsI+Hxej0b*fZD9rsiP6D$mtM`A)9}spo~X)6xUR zc+Vq{#~mD8lL!-pVs#OiFf%EzQV04tuw4||Ns)GP>^h?d<^|@<+N9MN-&?}tB!y{O zT5Va9APv7r500MKnqQm^V~RKSB@L5hkwSdOnMYu}ZpOq9Pcw^#6X7O3*S;B4$JUsn znVdnzAko7faim8ap&23dR04mq7W*b|<Dnk^{Qh-BjrvJ8=6gfwLXt}n|tN9G`Ft)PEi5v{K_a5IbMt1uH>AgiY$OXi${1GQYyqpN6{=J^kw5S=q>E^;~oaEdw|RzQML{Xq3|CXO5VMH&(8$n z;|4vQRRCiO(eP2ARzsDG!VNC zg$$wh)b-H!ne7ucY)92Vl)T=dlM0^Zm$s zuy_cw(Ccl>`T3CT*z9ZcydszF;Se!?lY8r{{=q;D{e6lG7R}p&S{B&m3lz0#)KN_# z>Amdf=%4&83FhVEydVTv(B%|x3jI1+Jb+AZ83MzO*z8Dy|E-4{>G>r5w^iRD-}EZv6rc7bn2%&maYRBb~an)b!RCJ!GTCMwhv#LBV5^ep%9C+ z*{SEQ28svwzBRtwaQziSc0U1yX1sp$*)3v^&k4$Quqi`{5W0@xoUu$OQsvujS|cg1 z)QW!Nmo1!u`nv`_SFT*VY{GGz6j#YlqnbpNsmc@d;AP|!b>kGCQUxR^N54Q&|FCc@ zH4z*{^;1T_Q6g$oAv!N%vYTr?H5)GFMB?+8Hu5d3#N>h0EtVH15;`afZxK$pkD6q? z8tPsGRcr8*UVg7nc(D&hA!;rr=Il%Pno6aB*2`a;j73gHNs20N2cO%lp`6p)#-ZTl zM=j*bx^>y1rfets`VyxkIfYxe8mR{2hp&tNI(khDaQ~t}o)N^&Bp`qc`~v_3?g5TJ z0pLBr`6s|}4}kszIPU@Qp8)6{;QA8)-vf|80j_%h`X>On2e|(PpudFvsRH;975>zL z>z59|Kb7G6r3CO#Ex7Kr(E0mw3!J~b`I0elHZV4DHu%@e4t1Fqf4%7df;s+mE*YPo zyS;&tm5DQ@p^2G=EkDD4QyT-Ng)u*a8dwG(V=roAZt=|1(L~8pR@unY%81*TK~Uh1 z%ivD339Gw-J*(-jS1eAHCQe5D)S`+nB&hER+>}~GUpmevfwsqoh=V$oE!gJTZ zN3%0f{vvU<;%88ok*9RFv$M9caHiy7<7NZ00y&>jnmQWTn7G+FT2TVoxESt+bTl^Q zQ52K-bHF=@pTXSO*`9};-ObI7&5e`I&e4n=$j!~o4&Y$t;9$L@V0H4abvAHkwRNIl z_><2<{cko~C$?WYu^HLfuv@6J1K9xVe+l~Qy`hDjE#*CIU})#!%+FxRZD0xjLjbH? zMt7qFfhGV}z}=4(3;=S?G008hWN%sGy;eUv_yKpCq^G+7uU6)7R(azY#$iz`V zQvL;{q`94w^B0g8Yj^+Qj3|Fvd;-j7)!A{~LkK$Nro4|9kgyH(URF zKX+d6r|tOeXn17oj4ez(#0;EG1ULXdAS(dG3glJ>KzYC*9`HTL1Gu}b-zbrPv5NkB z!T3L6{Wr>gW3_WszVjmic`=DUK}yy8my&n)3}oYA`*+qqDgXa8mw~;E%>UhBHa7Rm z;GT|0%+AQg#>Ce7x!C_u3j6<_rp88pt7-4zX#Hy)85^;iSex8y%-BOX&b zM;n8?!42%~tu2fUe(i?4bHBTJzq{yc;cRUp@JlCQYv(^Y))x07c&rU<&G;GIS&dCh z4P30983aTOoXr0)y|u-kbMT9Y{a@qU^^E?Qs6U2MGI988OaVDJTNB6M__rEvLzoPryqk^Bo?LKxtco6>E zw|f4HGmQTfikOhue=VIm8{DruMlqiIH3|R$xdBix=-2XO000>7$nMtle?y^sKgo>R zoDi;f+1ni{}TrWazKCM1wo-)59k0K_g^>t58N*~zvDPLxq!d(a&g>$JMK3e00eoU3l|sk z0S?Oj5C`G-O)ijw0|flt1{~ag`)|bkCyo;U{Ovw~oM6cPr-*-}k^k8iPAzTmr z0P--_0ihfZd>jOR@Ep98@lVg+hp_|*<$mbn-2dQf+~5c61N2~i@4OEL{y#$xD`PVw zGXsoz&>S5S_EugD(DAiR;7X(KMMLm`S~RZ z;5$bZ^gZ*^@)f{0N^ 0 && sourcenest >= sourcenest_max) + { + internal_error (_("%s: maximum source nesting level exceeded (%d)"), this_command_name, sourcenest); + sourcenest = 0; + jump_to_top_level (DISCARD); + } + unwind_protect_int (sourcenest); + /* The test for subshell == 0 above doesn't make a difference */ + sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */ + } + /* `return' does a longjmp() back to a saved environment in execute_function. If a variable assignment list preceded the command, and the shell is @@ -4698,6 +4714,8 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, login_shell = interactive = 0; if (builtin == eval_builtin) evalnest = 0; + else if (builtin == source_builtin) + sourcenest = 0; if (async) subshell_environment |= SUBSHELL_ASYNC; @@ -5222,7 +5240,7 @@ initialize_subshell () parse_and_execute_level = 0; /* nothing left to restore it */ /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = funcnest = evalnest = 0; + variable_context = return_catch_flag = funcnest = evalnest = sourcenest = 0; executing_list = 0; /* XXX */ diff --git a/lib/readline/doc/Makefile.old b/lib/readline/doc/Makefile.old new file mode 100644 index 000000000..58d4dd762 --- /dev/null +++ b/lib/readline/doc/Makefile.old @@ -0,0 +1,76 @@ +# This makefile for Readline library documentation is in -*- text -*- mode. +# Emacs likes it that way. +RM = rm -f + +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +TEXI2HTML = texi2html +QUIETPS = #set this to -q to shut up dvips +DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky + +INSTALL_DATA = cp +infodir = /usr/local/info + +RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo +HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo + +DVIOBJ = readline.dvi history.dvi +INFOOBJ = readline.info history.info +PSOBJ = readline.ps history.ps +HTMLOBJ = readline.html history.html + +all: info dvi html ps +nodvi: info html + +readline.dvi: $(RLSRC) + $(TEXI2DVI) rlman.texinfo + mv rlman.dvi readline.dvi + +readline.info: $(RLSRC) + $(MAKEINFO) --no-split -o $@ rlman.texinfo + +history.dvi: ${HISTSRC} + $(TEXI2DVI) hist.texinfo + mv hist.dvi history.dvi + +history.info: ${HISTSRC} + $(MAKEINFO) --no-split -o $@ hist.texinfo + +readline.ps: readline.dvi + $(RM) $@ + $(DVIPS) readline.dvi + +history.ps: history.dvi + $(RM) $@ + $(DVIPS) history.dvi + +readline.html: ${RLSRC} + $(TEXI2HTML) rlman.texinfo + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html + $(RM) rlman.html rlman_toc.html + +history.html: ${HISTSRC} + $(TEXI2HTML) hist.texinfo + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html + $(RM) hist.html hist_toc.html + +info: $(INFOOBJ) +dvi: $(DVIOBJ) +ps: $(PSOBJ) +html: $(HTMLOBJ) + +clean: + $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ + *.fns *.kys *.tps *.vrs *.o core + +distclean: clean +mostlyclean: clean + +maintainer-clean: clean + $(RM) *.dvi *.info *.info-* *.ps *.html + +install: info + ${INSTALL_DATA} readline.info $(infodir)/readline.info + ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/history.c b/lib/readline/history.c index 1181e7ccf..ece68fee3 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -48,6 +48,9 @@ #include "xmalloc.h" +/* How big to make the_history when we first allocate it. */ +#define DEFAULT_HISTORY_INITIAL_SIZE 502 + /* The number of slots to increase the_history by. */ #define DEFAULT_HISTORY_GROW_SIZE 50 @@ -289,7 +292,10 @@ add_history (string) { if (history_size == 0) { - history_size = DEFAULT_HISTORY_GROW_SIZE; + if (history_stifled && history_max_entries > 0) + history_size = history_max_entries + 2; + else + history_size = DEFAULT_HISTORY_INITIAL_SIZE; the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); history_length = 1; } diff --git a/pcomplete.c b/pcomplete.c index d4b31a66d..53866b316 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -300,7 +300,11 @@ filter_stringlist (sl, filterpat, text) npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; +#if defined (EXTENDED_GLOB) + not = (npat[0] == '!' && (extended_glob == 0 || npat[1] != '(')); /*)*/ +#else not = (npat[0] == '!'); +#endif t = not ? npat + 1 : npat; ret = strlist_create (sl->list_size); diff --git a/subst.h b/subst.h index 6a4110e39..d8103b799 100644 --- a/subst.h +++ b/subst.h @@ -47,6 +47,7 @@ #define ASS_MKASSOC 0x0004 #define ASS_MKGLOBAL 0x0008 /* force global assignment */ #define ASS_NAMEREF 0x0010 /* assigning to nameref variable */ +#define ASS_FROMREF 0x0020 /* assigning from value of nameref variable */ /* Flags for the string extraction functions. */ #define SX_NOALLOC 0x0001 /* just skip; don't return substring */ diff --git a/subst.h~ b/subst.h~ new file mode 100644 index 000000000..6a4110e39 --- /dev/null +++ b/subst.h~ @@ -0,0 +1,320 @@ +/* subst.h -- Names of externally visible functions in subst.c. */ + +/* Copyright (C) 1993-2010 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#if !defined (_SUBST_H_) +#define _SUBST_H_ + +#include "stdc.h" + +/* Constants which specify how to handle backslashes and quoting in + expand_word_internal (). Q_DOUBLE_QUOTES means to use the function + slashify_in_quotes () to decide whether the backslash should be + retained. Q_HERE_DOCUMENT means slashify_in_here_document () to + decide whether to retain the backslash. Q_KEEP_BACKSLASH means + to unconditionally retain the backslash. Q_PATQUOTE means that we're + expanding a pattern ${var%#[#%]pattern} in an expansion surrounded + by double quotes. Q_DOLBRACE means we are expanding a ${...} word, so + backslashes should also escape { and } and be removed. */ +#define Q_DOUBLE_QUOTES 0x01 +#define Q_HERE_DOCUMENT 0x02 +#define Q_KEEP_BACKSLASH 0x04 +#define Q_PATQUOTE 0x08 +#define Q_QUOTED 0x10 +#define Q_ADDEDQUOTES 0x20 +#define Q_QUOTEDNULL 0x40 +#define Q_DOLBRACE 0x80 + +/* Flag values controlling how assignment statements are treated. */ +#define ASS_APPEND 0x0001 +#define ASS_MKLOCAL 0x0002 +#define ASS_MKASSOC 0x0004 +#define ASS_MKGLOBAL 0x0008 /* force global assignment */ +#define ASS_NAMEREF 0x0010 /* assigning to nameref variable */ + +/* Flags for the string extraction functions. */ +#define SX_NOALLOC 0x0001 /* just skip; don't return substring */ +#define SX_VARNAME 0x0002 /* variable name; for string_extract () */ +#define SX_REQMATCH 0x0004 /* closing/matching delimiter required */ +#define SX_COMMAND 0x0008 /* extracting a shell script/command */ +#define SX_NOCTLESC 0x0010 /* don't honor CTLESC quoting */ +#define SX_NOESCCTLNUL 0x0020 /* don't let CTLESC quote CTLNUL */ +#define SX_NOLONGJMP 0x0040 /* don't longjmp on fatal error */ +#define SX_ARITHSUB 0x0080 /* extracting $(( ... )) (currently unused) */ +#define SX_POSIXEXP 0x0100 /* extracting new Posix pattern removal expansions in extract_dollar_brace_string */ +#define SX_WORD 0x0200 /* extracting word in ${param op word} */ + +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +extern char * de_backslash __P((char *)); + +/* Replace instances of \! in a string with !. */ +extern void unquote_bang __P((char *)); + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position just after the matching ")". + XFLAGS is additional flags to pass to other extraction functions, */ +extern char *extract_command_subst __P((char *, int *, int)); + +/* Extract the $[ construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position just after the matching "]". */ +extern char *extract_arithmetic_subst __P((char *, int *)); + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position just after the matching ")". */ +extern char *extract_process_subst __P((char *, char *, int *, int)); +#endif /* PROCESS_SUBSTITUTION */ + +/* Extract the name of the variable to bind to from the assignment string. */ +extern char *assignment_name __P((char *)); + +/* Return a single string of all the words present in LIST, separating + each word with SEP. */ +extern char *string_list_internal __P((WORD_LIST *, char *)); + +/* Return a single string of all the words present in LIST, separating + each word with a space. */ +extern char *string_list __P((WORD_LIST *)); + +/* Turn $* into a single string, obeying POSIX rules. */ +extern char *string_list_dollar_star __P((WORD_LIST *)); + +/* Expand $@ into a single string, obeying POSIX rules. */ +extern char *string_list_dollar_at __P((WORD_LIST *, int)); + +/* Turn the positional paramters into a string, understanding quoting and + the various subtleties of using the first character of $IFS as the + separator. Calls string_list_dollar_at, string_list_dollar_star, and + string_list as appropriate. */ +extern char *string_list_pos_params __P((int, WORD_LIST *, int)); + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +extern void word_list_remove_quoted_nulls __P((WORD_LIST *)); + +/* This performs word splitting and quoted null character removal on + STRING. */ +extern WORD_LIST *list_string __P((char *, char *, int)); + +extern char *ifs_firstchar __P((int *)); +extern char *get_word_from_string __P((char **, char *, char **)); +extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); + +/* Given STRING, an assignment string, get the value of the right side + of the `=', and bind it to the left side. If EXPAND is true, then + perform tilde expansion, parameter expansion, command substitution, + and arithmetic expansion on the right-hand side. Do not perform word + splitting on the result of expansion. */ +extern int do_assignment __P((char *)); +extern int do_assignment_no_expand __P((char *)); +extern int do_word_assignment __P((WORD_DESC *, int)); + +/* Append SOURCE to TARGET at INDEX. SIZE is the current amount + of space allocated to TARGET. SOURCE can be NULL, in which + case nothing happens. Gets rid of SOURCE by free ()ing it. + Returns TARGET in case the location has changed. */ +extern char *sub_append_string __P((char *, char *, int *, int *)); + +/* Append the textual representation of NUMBER to TARGET. + INDEX and SIZE are as in SUB_APPEND_STRING. */ +extern char *sub_append_number __P((intmax_t, char *, int *, int *)); + +/* Return the word list that corresponds to `$*'. */ +extern WORD_LIST *list_rest_of_args __P((void)); + +/* Make a single large string out of the dollar digit variables, + and the rest_of_args. If DOLLAR_STAR is 1, then obey the special + case of "$*" with respect to IFS. */ +extern char *string_rest_of_args __P((int)); + +extern int number_of_args __P((void)); + +/* Expand STRING by performing parameter expansion, command substitution, + and arithmetic expansion. Dequote the resulting WORD_LIST before + returning it, but do not perform word splitting. The call to + remove_quoted_nulls () is made here because word splitting normally + takes care of quote removal. */ +extern WORD_LIST *expand_string_unsplit __P((char *, int)); + +/* Expand the rhs of an assignment statement. */ +extern WORD_LIST *expand_string_assignment __P((char *, int)); + +/* Expand a prompt string. */ +extern WORD_LIST *expand_prompt_string __P((char *, int, int)); + +/* Expand STRING just as if you were expanding a word. This also returns + a list of words. Note that filename globbing is *NOT* done for word + or string expansion, just when the shell is expanding a command. This + does parameter expansion, command substitution, arithmetic expansion, + and word splitting. Dequote the resultant WORD_LIST before returning. */ +extern WORD_LIST *expand_string __P((char *, int)); + +/* Convenience functions that expand strings to strings, taking care of + converting the WORD_LIST * returned by the expand_string* functions + to a string and deallocating the WORD_LIST *. */ +extern char *expand_string_to_string __P((char *, int)); +extern char *expand_string_unsplit_to_string __P((char *, int)); +extern char *expand_assignment_string_to_string __P((char *, int)); + +/* Expand an arithmetic expression string */ +extern char *expand_arith_string __P((char *, int)); + +/* De-quote quoted characters in STRING. */ +extern char *dequote_string __P((char *)); + +/* De-quote CTLESC-escaped CTLESC or CTLNUL characters in STRING. */ +extern char *dequote_escapes __P((char *)); + +/* De-quote quoted characters in each word in LIST. */ +extern WORD_LIST *dequote_list __P((WORD_LIST *)); + +/* Expand WORD, performing word splitting on the result. This does + parameter expansion, command substitution, arithmetic expansion, + word splitting, and quote removal. */ +extern WORD_LIST *expand_word __P((WORD_DESC *, int)); + +/* Expand WORD, but do not perform word splitting on the result. This + does parameter expansion, command substitution, arithmetic expansion, + and quote removal. */ +extern WORD_LIST *expand_word_unsplit __P((WORD_DESC *, int)); +extern WORD_LIST *expand_word_leave_quoted __P((WORD_DESC *, int)); + +/* Return the value of a positional parameter. This handles values > 10. */ +extern char *get_dollar_var_value __P((intmax_t)); + +/* Quote a string to protect it from word splitting. */ +extern char *quote_string __P((char *)); + +/* Quote escape characters (characters special to interals of expansion) + in a string. */ +extern char *quote_escapes __P((char *)); + +/* And remove such quoted special characters. */ +extern char *remove_quoted_escapes __P((char *)); + +/* Remove CTLNUL characters from STRING unless they are quoted with CTLESC. */ +extern char *remove_quoted_nulls __P((char *)); + +/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the + backslash quoting rules for within double quotes. */ +extern char *string_quote_removal __P((char *, int)); + +/* Perform quote removal on word WORD. This allocates and returns a new + WORD_DESC *. */ +extern WORD_DESC *word_quote_removal __P((WORD_DESC *, int)); + +/* Perform quote removal on all words in LIST. If QUOTED is non-zero, + the members of the list are treated as if they are surrounded by + double quotes. Return a new list, or NULL if LIST is NULL. */ +extern WORD_LIST *word_list_quote_removal __P((WORD_LIST *, int)); + +/* Called when IFS is changed to maintain some private variables. */ +extern void setifs __P((SHELL_VAR *)); + +/* Return the value of $IFS, or " \t\n" if IFS is unset. */ +extern char *getifs __P((void)); + +/* This splits a single word into a WORD LIST on $IFS, but only if the word + is not quoted. list_string () performs quote removal for us, even if we + don't do any splitting. */ +extern WORD_LIST *word_split __P((WORD_DESC *, char *)); + +/* Take the list of words in LIST and do the various substitutions. Return + a new list of words which is the expanded list, and without things like + variable assignments. */ +extern WORD_LIST *expand_words __P((WORD_LIST *)); + +/* Same as expand_words (), but doesn't hack variable or environment + variables. */ +extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *)); + +/* Perform the `normal shell expansions' on a WORD_LIST. These are + brace expansion, tilde expansion, parameter and variable substitution, + command substitution, arithmetic expansion, and word splitting. */ +extern WORD_LIST *expand_words_shellexp __P((WORD_LIST *)); + +extern WORD_DESC *command_substitute __P((char *, int)); +extern char *pat_subst __P((char *, char *, char *, int)); + +extern int fifos_pending __P((void)); +extern int num_fifos __P((void)); +extern void unlink_fifo_list __P((void)); +extern void unlink_fifo __P((int)); + +extern char *copy_fifo_list __P((int *)); +extern void unlink_new_fifos __P((char *, int)); +extern void close_new_fifos __P((char *, int)); + +extern void clear_fifo_list __P((void)); + +extern WORD_LIST *list_string_with_quotes __P((char *)); + +#if defined (ARRAY_VARS) +extern char *extract_array_assignment_list __P((char *, int *)); +#endif + +#if defined (COND_COMMAND) +extern char *remove_backslashes __P((char *)); +extern char *cond_expand_word __P((WORD_DESC *, int)); +#endif + +/* Flags for skip_to_delim */ +#define SD_NOJMP 0x01 /* don't longjmp on fatal error. */ +#define SD_INVERT 0x02 /* look for chars NOT in passed set */ +#define SD_NOQUOTEDELIM 0x04 /* don't let single or double quotes act as delimiters */ +#define SD_NOSKIPCMD 0x08 /* don't skip over $(, <(, or >( command/process substitution; parse them as commands */ +#define SD_EXTGLOB 0x10 /* skip over extended globbing patterns if appropriate */ +#define SD_IGNOREQUOTE 0x20 /* single and double quotes are not special */ +#define SD_GLOB 0x40 /* skip over glob patterns like bracket expressions */ +#define SD_NOPROCSUB 0x80 /* don't parse process substitutions as commands */ + +extern int skip_to_delim __P((char *, int, char *, int)); + +#if defined (READLINE) +extern int char_is_quoted __P((char *, int)); +extern int unclosed_pair __P((char *, int, char *)); +extern WORD_LIST *split_at_delims __P((char *, int, char *, int, int, int *, int *)); +#endif + +/* Variables used to keep track of the characters in IFS. */ +extern SHELL_VAR *ifs_var; +extern char *ifs_value; +extern unsigned char ifs_cmap[]; + +#if defined (HANDLE_MULTIBYTE) +extern unsigned char ifs_firstc[]; +extern size_t ifs_firstc_len; +#else +extern unsigned char ifs_firstc; +#endif + +/* Evaluates to 1 if C is a character in $IFS. */ +#define isifs(c) (ifs_cmap[(unsigned char)(c)] != 0) + +/* How to determine the quoted state of the character C. */ +#define QUOTED_CHAR(c) ((c) == CTLESC) + +/* Is the first character of STRING a quoted NULL character? */ +#define QUOTED_NULL(string) ((string)[0] == CTLNUL && (string)[1] == '\0') + +#endif /* !_SUBST_H_ */ diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig new file mode 100644 index 000000000..c1f1e1991 --- /dev/null +++ b/tests/misc/regress/log.orig @@ -0,0 +1,50 @@ +:; ./shx + +sh: +<&$fd ok +nlbq Mon Aug 3 02:45:00 EDT 1992 +bang geoff +quote 712824302 +setbq defmsgid=<1992Aug3.024502.6176@host> +bgwait sleep done... wait 6187 + + +bash: +<&$fd ok +nlbq Mon Aug 3 02:45:09 EDT 1992 +bang geoff +quote 712824311 +setbq defmsgid=<1992Aug3.024512.6212@host> +bgwait sleep done... wait 6223 + + +ash: +<&$fd shx1: 4: Syntax error: Bad fd number +nlbq Mon Aug 3 02:45:19 EDT 1992 +bang geoff +quote getdate: `"now"' not a valid date + +setbq defmsgid=<1992Aug3.` echo 024521 +bgwait sleep done... wait 6241 + + +ksh: +<&$fd ok +nlbq ./shx: 6248 Memory fault - core dumped +bang geoff +quote getdate: `"now"' not a valid date + +setbq defmsgid=<1992Aug3.024530.6257@host> +bgwait no such job: 6265 +wait 6265 +sleep done... + +zsh: +<&$fd ok +nlbq Mon Aug 3 02:45:36 EDT 1992 +bang shx3: event not found: /s/ [4] +quote 712824337 +setbq defmsgid=<..6290@host> +bgwait shx7: unmatched " [9] +sleep done... +:; diff --git a/tests/misc/regress/shx.orig b/tests/misc/regress/shx.orig new file mode 100644 index 000000000..4b3bf2b82 --- /dev/null +++ b/tests/misc/regress/shx.orig @@ -0,0 +1,10 @@ +#! /bin/sh +for cmd in sh bash ash ksh zsh +do + echo + echo $cmd: + for demo in shx? + do + $cmd $demo + done +done diff --git a/tests/parser.right b/tests/parser.right new file mode 100644 index 000000000..43d5a8ed6 --- /dev/null +++ b/tests/parser.right @@ -0,0 +1 @@ +AAA diff --git a/tests/parser.tests b/tests/parser.tests new file mode 100644 index 000000000..12ff88c29 --- /dev/null +++ b/tests/parser.tests @@ -0,0 +1,4 @@ +# catch-all for parsing problems that don't fit anywhere else + +# this has to be in a separate file to get desired EOF behavior +${THIS_SH} ./parser1.sub diff --git a/tests/parser1.sub b/tests/parser1.sub new file mode 100644 index 000000000..503193166 --- /dev/null +++ b/tests/parser1.sub @@ -0,0 +1 @@ +eval "array=(foo bar)" ; echo AAA\ diff --git a/tests/run-parser b/tests/run-parser new file mode 100644 index 000000000..7834c9117 --- /dev/null +++ b/tests/run-parser @@ -0,0 +1,2 @@ +${THIS_SH} ./parser.tests > /tmp/xx 2>&1 +diff /tmp/xx parser.right && rm -f /tmp/xx diff --git a/variables.c b/variables.c index 03ff67dc9..448595283 100644 --- a/variables.c +++ b/variables.c @@ -2687,6 +2687,7 @@ bind_variable (name, value, flags) SHELL_VAR *v, *nv; VAR_CONTEXT *vc, *nvc; int level; + char *newname; if (shell_variables == 0) create_variable_tables (); @@ -2719,6 +2720,11 @@ bind_variable (name, value, flags) normal. */ if (nameref_cell (nv) == 0) return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv))) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); } else diff --git a/variables.c~ b/variables.c~ new file mode 100644 index 000000000..448595283 --- /dev/null +++ b/variables.c~ @@ -0,0 +1,5399 @@ +/* variables.c -- Functions for hacking shell variables. */ + +/* Copyright (C) 1987-2013 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include "config.h" + +#include "bashtypes.h" +#include "posixstat.h" +#include "posixtime.h" + +#if defined (__QNX__) +# if defined (__QNXNTO__) +# include +# else +# include +# endif /* !__QNXNTO__ */ +#endif /* __QNX__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "chartypes.h" +#if defined (HAVE_PWD_H) +# include +#endif +#include "bashansi.h" +#include "bashintl.h" + +#define NEED_XTRACE_SET_DECL + +#include "shell.h" +#include "flags.h" +#include "execute_cmd.h" +#include "findcmd.h" +#include "mailcheck.h" +#include "input.h" +#include "hashcmd.h" +#include "pathexp.h" +#include "alias.h" +#include "jobs.h" + +#include "version.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#if defined (READLINE) +# include "bashline.h" +# include +#else +# include +#endif + +#if defined (HISTORY) +# include "bashhist.h" +# include +#endif /* HISTORY */ + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ + +#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') + +/* flags for find_variable_internal */ + +#define FV_FORCETEMPENV 0x01 +#define FV_SKIPINVISIBLE 0x02 + +extern char **environ; + +/* Variables used here and defined in other files. */ +extern int posixly_correct; +extern int line_number, line_number_base; +extern int subshell_environment, indirection_level, subshell_level; +extern int build_version, patch_level; +extern int expanding_redir; +extern int last_command_exit_value; +extern char *dist_version, *release_status; +extern char *shell_name; +extern char *primary_prompt, *secondary_prompt; +extern char *current_host_name; +extern sh_builtin_func_t *this_shell_builtin; +extern SHELL_VAR *this_shell_function; +extern char *the_printed_command_except_trap; +extern char *this_command_name; +extern char *command_execution_string; +extern time_t shell_start_time; +extern int assigning_in_environment; +extern int executing_builtin; +extern int funcnest_max; + +#if defined (READLINE) +extern int no_line_editing; +extern int perform_hostname_completion; +#endif + +/* The list of shell variables that the user has created at the global + scope, or that came from the environment. */ +VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; + +/* The current list of shell variables, including function scopes */ +VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; + +/* The list of shell functions that the user has created, or that came from + the environment. */ +HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; + +#if defined (DEBUGGER) +/* The table of shell function definitions that the user defined or that + came from the environment. */ +HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; +#endif + +/* The current variable context. This is really a count of how deep into + executing functions we are. */ +int variable_context = 0; + +/* The set of shell assignments which are made only in the environment + for a single command. */ +HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; + +/* Set to non-zero if an assignment error occurs while putting variables + into the temporary environment. */ +int tempenv_assign_error; + +/* Some funky variables which are known about specially. Here is where + "$*", "$1", and all the cruft is kept. */ +char *dollar_vars[10]; +WORD_LIST *rest_of_args = (WORD_LIST *)NULL; + +/* The value of $$. */ +pid_t dollar_dollar_pid; + +/* Non-zero means that we have to remake EXPORT_ENV. */ +int array_needs_making = 1; + +/* The number of times BASH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; + +/* An array which is passed to commands as their environment. It is + manufactured from the union of the initial environment and the + shell variables that are marked for export. */ +char **export_env = (char **)NULL; +static int export_env_index; +static int export_env_size; + +#if defined (READLINE) +static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ +#endif + +static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ + +/* Some forward declarations. */ +static void create_variable_tables __P((void)); + +static void set_machine_vars __P((void)); +static void set_home_var __P((void)); +static void set_shell_var __P((void)); +static char *get_bash_name __P((void)); +static void initialize_shell_level __P((void)); +static void uidset __P((void)); +#if defined (ARRAY_VARS) +static void make_vers_array __P((void)); +#endif + +static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); +#if defined (ARRAY_VARS) +static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); +#endif +static SHELL_VAR *get_self __P((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); +#endif + +static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_seconds __P((SHELL_VAR *)); +static SHELL_VAR *init_seconds_var __P((void)); + +static int brand __P((void)); +static void sbrand __P((unsigned long)); /* set bash random number generator. */ +static void seedrand __P((void)); /* seed generator randomly */ +static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_random __P((SHELL_VAR *)); + +static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_lineno __P((SHELL_VAR *)); + +static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_subshell __P((SHELL_VAR *)); + +static SHELL_VAR *get_bashpid __P((SHELL_VAR *)); + +#if defined (HISTORY) +static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); +#endif + +#if defined (READLINE) +static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *)); +static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *)); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *)); +static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); +#endif + +#if defined (ARRAY_VARS) +static SHELL_VAR *get_groupset __P((SHELL_VAR *)); + +static SHELL_VAR *build_hashcmd __P((SHELL_VAR *)); +static SHELL_VAR *get_hashcmd __P((SHELL_VAR *)); +static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *)); +# if defined (ALIAS) +static SHELL_VAR *build_aliasvar __P((SHELL_VAR *)); +static SHELL_VAR *get_aliasvar __P((SHELL_VAR *)); +static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *)); +# endif +#endif + +static SHELL_VAR *get_funcname __P((SHELL_VAR *)); +static SHELL_VAR *init_funcname_var __P((void)); + +static void initialize_dynamic_variables __P((void)); + +static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *)); +static SHELL_VAR *new_shell_variable __P((const char *)); +static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *)); +static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int)); + +static void dispose_variable_value __P((SHELL_VAR *)); +static void free_variable_hash_data __P((PTR_T)); + +static VARLIST *vlist_alloc __P((int)); +static VARLIST *vlist_realloc __P((VARLIST *, int)); +static void vlist_add __P((VARLIST *, SHELL_VAR *, int)); + +static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); + +static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **)); + +static SHELL_VAR **vapply __P((sh_var_map_func_t *)); +static SHELL_VAR **fapply __P((sh_var_map_func_t *)); + +static int visible_var __P((SHELL_VAR *)); +static int visible_and_exported __P((SHELL_VAR *)); +static int export_environment_candidate __P((SHELL_VAR *)); +static int local_and_exported __P((SHELL_VAR *)); +static int variable_in_context __P((SHELL_VAR *)); +#if defined (ARRAY_VARS) +static int visible_array_vars __P((SHELL_VAR *)); +#endif + +static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *)); +static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); +static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); + +static SHELL_VAR *bind_tempenv_variable __P((const char *, char *)); +static void push_temp_var __P((PTR_T)); +static void propagate_temp_var __P((PTR_T)); +static void dispose_temporary_env __P((sh_free_func_t *)); + +static inline char *mk_env_string __P((const char *, const char *)); +static char **make_env_array_from_var_list __P((SHELL_VAR **)); +static char **make_var_export_array __P((VAR_CONTEXT *)); +static char **make_func_export_array __P((void)); +static void add_temp_array_to_env __P((char **, int, int)); + +static int n_shell_variables __P((void)); +static int set_context __P((SHELL_VAR *)); + +static void push_func_var __P((PTR_T)); +static void push_exported_var __P((PTR_T)); + +static inline int find_special_var __P((const char *)); + +static void +create_variable_tables () +{ + if (shell_variables == 0) + { + shell_variables = global_variables = new_var_context ((char *)NULL, 0); + shell_variables->scope = 0; + shell_variables->table = hash_create (0); + } + + if (shell_functions == 0) + shell_functions = hash_create (0); + +#if defined (DEBUGGER) + if (shell_function_defs == 0) + shell_function_defs = hash_create (0); +#endif +} + +/* Initialize the shell variables from the current environment. + If PRIVMODE is nonzero, don't import functions from ENV or + parse $SHELLOPTS. */ +void +initialize_shell_variables (env, privmode) + char **env; + int privmode; +{ + char *name, *string, *temp_string; + int c, char_index, string_index, string_length, ro; + SHELL_VAR *temp_var; + + create_variable_tables (); + + for (string_index = 0; string = env[string_index++]; ) + { + char_index = 0; + name = string; + while ((c = *string++) && c != '=') + ; + if (string[-1] == '=') + char_index = string - name - 1; + + /* If there are weird things in the environment, like `=xxx' or a + string without an `=', just skip them. */ + if (char_index == 0) + continue; + + /* ASSERT(name[char_index] == '=') */ + name[char_index] = '\0'; + /* Now, name = env variable name, string = env variable value, and + char_index == strlen (name) */ + + temp_var = (SHELL_VAR *)NULL; + + /* If exported function, define it now. Don't import functions from + the environment in privileged mode. */ + if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) + { + string_length = strlen (string); + temp_string = (char *)xmalloc (3 + string_length + char_index); + + strcpy (temp_string, name); + temp_string[char_index] = ' '; + strcpy (temp_string + char_index + 1, string); + + if (posixly_correct == 0 || legal_identifier (name)) + parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST); + + /* Ancient backwards compatibility. Old versions of bash exported + functions like name()=() {...} */ + if (name[char_index - 1] == ')' && name[char_index - 2] == '(') + name[char_index - 2] = '\0'; + + if (temp_var = find_function (name)) + { + VSETATTR (temp_var, (att_exported|att_imported)); + array_needs_making = 1; + } + else + { + if (temp_var = bind_variable (name, string, 0)) + { + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + array_needs_making = 1; + } + last_command_exit_value = 1; + report_error (_("error importing function definition for `%s'"), name); + } + + /* ( */ + if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') + name[char_index - 2] = '('; /* ) */ + } +#if defined (ARRAY_VARS) +# if ARRAY_EXPORT + /* Array variables may not yet be exported. */ + else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string); + FREE (temp_string); + VSETATTR (temp_var, (att_exported | att_imported)); + array_needs_making = 1; + } +# endif /* ARRAY_EXPORT */ +#endif +#if 0 + else if (legal_identifier (name)) +#else + else +#endif + { + ro = 0; + if (posixly_correct && STREQ (name, "SHELLOPTS")) + { + temp_var = find_variable ("SHELLOPTS"); + ro = temp_var && readonly_p (temp_var); + if (temp_var) + VUNSETATTR (temp_var, att_readonly); + } + temp_var = bind_variable (name, string, 0); + if (temp_var) + { + if (legal_identifier (name)) + VSETATTR (temp_var, (att_exported | att_imported)); + else + VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); + if (ro) + VSETATTR (temp_var, att_readonly); + array_needs_making = 1; + } + } + + name[char_index] = '='; + /* temp_var can be NULL if it was an exported function with a syntax + error (a different bug, but it still shouldn't dump core). */ + if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ + { + CACHE_IMPORTSTR (temp_var, name); + } + } + + set_pwd (); + + /* Set up initial value of $_ */ + temp_var = set_if_not ("_", dollar_vars[0]); + + /* Remember this pid. */ + dollar_dollar_pid = getpid (); + + /* Now make our own defaults in case the vars that we think are + important are missing. */ + temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); +#if 0 + set_auto_export (temp_var); /* XXX */ +#endif + + temp_var = set_if_not ("TERM", "dumb"); +#if 0 + set_auto_export (temp_var); /* XXX */ +#endif + +#if defined (__QNX__) + /* set node id -- don't import it from the environment */ + { + char node_name[22]; +# if defined (__QNXNTO__) + netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); +# else + qnx_nidtostr (getnid (), node_name, sizeof (node_name)); +# endif + temp_var = bind_variable ("NODE", node_name, 0); + set_auto_export (temp_var); + } +#endif + + /* set up the prompts. */ + if (interactive_shell) + { +#if defined (PROMPT_STRING_DECODE) + set_if_not ("PS1", primary_prompt); +#else + if (current_user.uid == -1) + get_current_user_info (); + set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); +#endif + set_if_not ("PS2", secondary_prompt); + } + set_if_not ("PS4", "+ "); + + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n", 0); + setifs (temp_var); + + /* Magic machine types. Pretty convenient. */ + set_machine_vars (); + + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILPATH is not set, and we should provide a + default only if neither is set. */ + if (interactive_shell) + { + temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); + VSETATTR (temp_var, att_integer); + } + + /* Do some things with shell level. */ + initialize_shell_level (); + + set_ppid (); + + /* Initialize the `getopts' stuff. */ + temp_var = bind_variable ("OPTIND", "1", 0); + VSETATTR (temp_var, att_integer); + getopts_reset (0); + bind_variable ("OPTERR", "1", 0); + sh_opterr = 1; + + if (login_shell == 1 && posixly_correct == 0) + set_home_var (); + + /* Get the full pathname to THIS shell, and set the BASH variable + to it. */ + name = get_bash_name (); + temp_var = bind_variable ("BASH", name, 0); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + set_shell_var (); + + /* Make a variable called BASH_VERSION which contains the version info. */ + bind_variable ("BASH_VERSION", shell_version_string (), 0); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif + + if (command_execution_string) + bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0); + + /* Find out if we're supposed to be in Posix.2 mode via an + environment variable. */ + temp_var = find_variable ("POSIXLY_CORRECT"); + if (!temp_var) + temp_var = find_variable ("POSIX_PEDANTIC"); + if (temp_var && imported_p (temp_var)) + sv_strict_posix (temp_var->name); + +#if defined (HISTORY) + /* Set history variables to defaults, and then do whatever we would + do if the variable had just been set. Do this only in the case + that we are remembering commands on the history list. */ + if (remember_on_history) + { + name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0); + + set_if_not ("HISTFILE", name); + free (name); + } +#endif /* HISTORY */ + + /* Seed the random number generator. */ + seedrand (); + + /* Handle some "special" variables that we may have inherited from a + parent shell. */ + if (interactive_shell) + { + temp_var = find_variable ("IGNOREEOF"); + if (!temp_var) + temp_var = find_variable ("ignoreeof"); + if (temp_var && imported_p (temp_var)) + sv_ignoreeof (temp_var->name); + } + +#if defined (HISTORY) + if (interactive_shell && remember_on_history) + { + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); + sv_histtimefmt ("HISTTIMEFORMAT"); + } +#endif /* HISTORY */ + +#if defined (READLINE) && defined (STRICT_POSIX) + /* POSIXLY_CORRECT will only be 1 here if the shell was compiled + -DSTRICT_POSIX */ + if (interactive_shell && posixly_correct && no_line_editing == 0) + rl_prefer_env_winsize = 1; +#endif /* READLINE && STRICT_POSIX */ + + /* + * 24 October 2001 + * + * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT + * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in + * isnetconn() to avoid running the startup files more often than wanted. + * That will, of course, only work if the user's login shell is bash, so + * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined + * in config-top.h. + */ +#if 0 + temp_var = find_variable ("SSH_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } + temp_var = find_variable ("SSH2_CLIENT"); + if (temp_var && imported_p (temp_var)) + { + VUNSETATTR (temp_var, att_exported); + array_needs_making = 1; + } +#endif + + /* Get the user's real and effective user ids. */ + uidset (); + + temp_var = find_variable ("BASH_XTRACEFD"); + if (temp_var && imported_p (temp_var)) + sv_xtracefd (temp_var->name); + + /* Initialize the dynamic variables, and seed their values. */ + initialize_dynamic_variables (); +} + +/* **************************************************************** */ +/* */ +/* Setting values for special shell variables */ +/* */ +/* **************************************************************** */ + +static void +set_machine_vars () +{ + SHELL_VAR *temp_var; + + temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = set_if_not ("MACHTYPE", MACHTYPE); + + temp_var = set_if_not ("HOSTNAME", current_host_name); +} + +/* Set $HOME to the information in the password file if we didn't get + it from the environment. */ + +/* This function is not static so the tilde and readline libraries can + use it. */ +char * +sh_get_home_dir () +{ + if (current_user.home_dir == 0) + get_current_user_info (); + return current_user.home_dir; +} + +static void +set_home_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("HOME"); + if (temp_var == 0) + temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +/* Set $SHELL to the user's login shell if it is not already set. Call + get_current_user_info if we haven't already fetched the shell. */ +static void +set_shell_var () +{ + SHELL_VAR *temp_var; + + temp_var = find_variable ("SHELL"); + if (temp_var == 0) + { + if (current_user.shell == 0) + get_current_user_info (); + temp_var = bind_variable ("SHELL", current_user.shell, 0); + } +#if 0 + VSETATTR (temp_var, att_exported); +#endif +} + +static char * +get_bash_name () +{ + char *name; + + if ((login_shell == 1) && RELPATH(shell_name)) + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + else if (ABSPATH(shell_name)) + name = savestring (shell_name); + else if (shell_name[0] == '.' && shell_name[1] == '/') + { + /* Fast path for common case. */ + char *cdir; + int len; + + cdir = get_string_value ("PWD"); + if (cdir) + { + len = strlen (cdir); + name = (char *)xmalloc (len + strlen (shell_name) + 1); + strcpy (name, cdir); + strcpy (name + len, shell_name + 1); + } + else + name = savestring (shell_name); + } + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (name == 0) + name = tname; + else + free (tname); + } + else + name = tname; + } + else + { + if (current_user.shell == 0) + get_current_user_info (); + name = savestring (current_user.shell); + } + } + else + { + name = full_pathname (tname); + free (tname); + } + } + + return (name); +} + +void +adjust_shell_level (change) + int change; +{ + char new_level[5], *old_SHLVL; + intmax_t old_level; + SHELL_VAR *temp_var; + + old_SHLVL = get_string_value ("SHLVL"); + if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) + old_level = 0; + + shell_level = old_level + change; + if (shell_level < 0) + shell_level = 0; + else if (shell_level > 1000) + { + internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); + shell_level = 1; + } + + /* We don't need the full generality of itos here. */ + if (shell_level < 10) + { + new_level[0] = shell_level + '0'; + new_level[1] = '\0'; + } + else if (shell_level < 100) + { + new_level[0] = (shell_level / 10) + '0'; + new_level[1] = (shell_level % 10) + '0'; + new_level[2] = '\0'; + } + else if (shell_level < 1000) + { + new_level[0] = (shell_level / 100) + '0'; + old_level = shell_level % 100; + new_level[1] = (old_level / 10) + '0'; + new_level[2] = (old_level % 10) + '0'; + new_level[3] = '\0'; + } + + temp_var = bind_variable ("SHLVL", new_level, 0); + set_auto_export (temp_var); +} + +static void +initialize_shell_level () +{ + adjust_shell_level (1); +} + +/* If we got PWD from the environment, update our idea of the current + working directory. In any case, make sure that PWD exists before + checking it. It is possible for getcwd () to fail on shell startup, + and in that case, PWD would be undefined. If this is an interactive + login shell, see if $HOME is the current working directory, and if + that's not the same string as $PWD, set PWD=$HOME. */ + +void +set_pwd () +{ + SHELL_VAR *temp_var, *home_var; + char *temp_string, *home_string; + + home_var = find_variable ("HOME"); + home_string = home_var ? value_cell (home_var) : (char *)NULL; + + temp_var = find_variable ("PWD"); + if (temp_var && imported_p (temp_var) && + (temp_string = value_cell (temp_var)) && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + set_working_directory (temp_string); + else if (home_string && interactive_shell && login_shell && + same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + { + set_working_directory (home_string); + temp_var = bind_variable ("PWD", home_string, 0); + set_auto_export (temp_var); + } + else + { + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + temp_var = bind_variable ("PWD", temp_string, 0); + set_auto_export (temp_var); + free (temp_string); + } + } + + /* According to the Single Unix Specification, v2, $OLDPWD is an + `environment variable' and therefore should be auto-exported. + Make a dummy invisible variable for OLDPWD, and mark it as exported. */ + temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); + VSETATTR (temp_var, (att_exported | att_invisible)); +} + +/* Make a variable $PPID, which holds the pid of the shell's parent. */ +void +set_ppid () +{ + char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; + SHELL_VAR *temp_var; + + name = inttostr (getppid (), namebuf, sizeof(namebuf)); + temp_var = find_variable ("PPID"); + if (temp_var) + VUNSETATTR (temp_var, (att_readonly | att_exported)); + temp_var = bind_variable ("PPID", name, 0); + VSETATTR (temp_var, (att_readonly | att_integer)); +} + +static void +uidset () +{ + char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; + register SHELL_VAR *v; + + b = inttostr (current_user.uid, buff, sizeof (buff)); + v = find_variable ("UID"); + if (v == 0) + { + v = bind_variable ("UID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } + + if (current_user.euid != current_user.uid) + b = inttostr (current_user.euid, buff, sizeof (buff)); + + v = find_variable ("EUID"); + if (v == 0) + { + v = bind_variable ("EUID", b, 0); + VSETATTR (v, (att_readonly | att_integer)); + } +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; + + unbind_variable ("BASH_VERSINFO"); + + vv = make_new_array_variable ("BASH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_insert (av, 0, d); + array_insert (av, 1, s); + s = inttostr (patch_level, b, sizeof (b)); + array_insert (av, 2, s); + s = inttostr (build_version, b, sizeof (b)); + array_insert (av, 3, s); + array_insert (av, 4, release_status); + array_insert (av, 5, MACHTYPE); + + VSETATTR (vv, att_readonly); +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char val[INT_STRLEN_BOUND(int) + 1], *v; + +#if defined (READLINE) + /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ + if (winsize_assignment) + return; +#endif + + v = inttostr (lines, val, sizeof (val)); + bind_variable ("LINES", v, 0); + + v = inttostr (cols, val, sizeof (val)); + bind_variable ("COLUMNS", v, 0); +} + +/* **************************************************************** */ +/* */ +/* Printing variables and values */ +/* */ +/* **************************************************************** */ + +/* Print LIST (a list of shell variables) to stdout in such a way that + they can be read back in. */ +void +print_var_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + if (invisible_p (var) == 0) + print_assignment (var); +} + +/* Print LIST (a list of shell functions) to stdout in such a way that + they can be read back in. */ +void +print_func_list (list) + register SHELL_VAR **list; +{ + register int i; + register SHELL_VAR *var; + + for (i = 0; list && (var = list[i]); i++) + { + printf ("%s ", var->name); + print_var_function (var); + printf ("\n"); + } +} + +/* Print the value of a single SHELL_VAR. No newline is + output, but the variable is printed in such a way that + it can be read back in. */ +void +print_assignment (var) + SHELL_VAR *var; +{ + if (var_isset (var) == 0) + return; + + if (function_p (var)) + { + printf ("%s", var->name); + print_var_function (var); + printf ("\n"); + } +#if defined (ARRAY_VARS) + else if (array_p (var)) + print_array_assignment (var, 0); + else if (assoc_p (var)) + print_assoc_assignment (var, 0); +#endif /* ARRAY_VARS */ + else + { + printf ("%s=", var->name); + print_var_value (var, 1); + printf ("\n"); + } +} + +/* Print the value cell of VAR, a shell variable. Do not print + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ +void +print_var_value (var, quote) + SHELL_VAR *var; + int quote; +{ + char *t; + + if (var_isset (var) == 0) + return; + + if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) + { + t = ansic_quote (value_cell (var), 0, (int *)0); + printf ("%s", t); + free (t); + } + else if (quote && sh_contains_shell_metas (value_cell (var))) + { + t = sh_single_quote (value_cell (var)); + printf ("%s", t); + free (t); + } + else + printf ("%s", value_cell (var)); +} + +/* Print the function cell of VAR, a shell variable. Do not + print the name, nor leading/trailing newline. */ +void +print_var_function (var) + SHELL_VAR *var; +{ + char *x; + + if (function_p (var) && var_isset (var)) + { + x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); + printf ("%s", x); + } +} + +/* **************************************************************** */ +/* */ +/* Dynamic Variables */ +/* */ +/* **************************************************************** */ + +/* DYNAMIC VARIABLES + + These are variables whose values are generated anew each time they are + referenced. These are implemented using a pair of function pointers + in the struct variable: assign_func, which is called from bind_variable + and, if arrays are compiled into the shell, some of the functions in + arrayfunc.c, and dynamic_value, which is called from find_variable. + + assign_func is called from bind_variable_internal, if + bind_variable_internal discovers that the variable being assigned to + has such a function. The function is called as + SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) + and the (SHELL_VAR *)temp is returned as the value of bind_variable. It + is usually ENTRY (self). IND is an index for an array variable, and + unused otherwise. + + dynamic_value is called from find_variable_internal to return a `new' + value for the specified dynamic varible. If this function is NULL, + the variable is treated as a `normal' shell variable. If it is not, + however, then this function is called like this: + tempvar = (*(var->dynamic_value)) (var); + + Sometimes `tempvar' will replace the value of `var'. Other times, the + shell will simply use the string value. Pretty object-oriented, huh? + + Be warned, though: if you `unset' a special variable, it loses its + special meaning, even if you subsequently set it. + + The special assignment code would probably have been better put in + subst.c: do_assignment_internal, in the same style as + stupidly_hack_special_variables, but I wanted the changes as + localized as possible. */ + +#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ + do \ + { \ + v = bind_variable (var, (val), 0); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_array_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ + do \ + { \ + v = make_new_assoc_variable (var); \ + v->dynamic_value = gfunc; \ + v->assign_func = afunc; \ + } \ + while (0) + +static SHELL_VAR * +null_assign (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + return (self); +} + +#if defined (ARRAY_VARS) +static SHELL_VAR * +null_array_assign (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + return (self); +} +#endif + +/* Degenerate `dynamic_value' function; just returns what's passed without + manipulation. */ +static SHELL_VAR * +get_self (self) + SHELL_VAR *self; +{ + return (self); +} + +#if defined (ARRAY_VARS) +/* A generic dynamic array variable initializer. Initialize array variable + NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ +static SHELL_VAR * +init_dynamic_array_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} + +static SHELL_VAR * +init_dynamic_assoc_var (name, getfunc, setfunc, attrs) + char *name; + sh_var_value_func_t *getfunc; + sh_var_assign_func_t *setfunc; + int attrs; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v) + return (v); + INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); + if (attrs) + VSETATTR (v, attrs); + return v; +} +#endif + +/* The value of $SECONDS. This is the number of seconds since shell + invocation, or, the number of seconds since the last assignment + the + value of the last assignment. */ +static intmax_t seconds_value_assigned; + +static SHELL_VAR * +assign_seconds (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (legal_number (value, &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + shell_start_time = NOW; + return (self); +} + +static SHELL_VAR * +get_seconds (var) + SHELL_VAR *var; +{ + time_t time_since_start; + char *p; + + time_since_start = NOW - shell_start_time; + p = itos(seconds_value_assigned + time_since_start); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +init_seconds_var () +{ + SHELL_VAR *v; + + v = find_variable ("SECONDS"); + if (v) + { + if (legal_number (value_cell(v), &seconds_value_assigned) == 0) + seconds_value_assigned = 0; + } + INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); + return v; +} + +/* The random number seed. You can change this by setting RANDOM. */ +static unsigned long rseed = 1; +static int last_random_value; +static int seeded_subshell = 0; + +/* A linear congruential random number generator based on the example + one in the ANSI C standard. This one isn't very good, but a more + complicated one is overkill. */ + +/* Returns a pseudo-random number between 0 and 32767. */ +static int +brand () +{ + /* From "Random number generators: good ones are hard to find", + Park and Miller, Communications of the ACM, vol. 31, no. 10, + October 1988, p. 1195. filtered through FreeBSD */ + long h, l; + + /* Can't seed with 0. */ + if (rseed == 0) + rseed = 123459876; + h = rseed / 127773; + l = rseed % 127773; + rseed = 16807 * l - 2836 * h; +#if 0 + if (rseed < 0) + rseed += 0x7fffffff; +#endif + return ((unsigned int)(rseed & 32767)); /* was % 32768 */ +} + +/* Set the random number generator seed to SEED. */ +static void +sbrand (seed) + unsigned long seed; +{ + rseed = seed; + last_random_value = 0; +} + +static void +seedrand () +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ()); +} + +static SHELL_VAR * +assign_random (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + sbrand (strtoul (value, (char **)NULL, 10)); + if (subshell_environment) + seeded_subshell = getpid (); + return (self); +} + +int +get_random_number () +{ + int rv, pid; + + /* Reset for command and process substitution. */ + pid = getpid (); + if (subshell_environment && seeded_subshell != pid) + { + seedrand (); + seeded_subshell = pid; + } + + do + rv = brand (); + while (rv == last_random_value); + return rv; +} + +static SHELL_VAR * +get_random (var) + SHELL_VAR *var; +{ + int rv; + char *p; + + rv = get_random_number (); + last_random_value = rv; + p = itos (rv); + + FREE (value_cell (var)); + + VSETATTR (var, att_integer); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_lineno (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + line_number = line_number_base = new_value; + return var; +} + +/* Function which returns the current line number. */ +static SHELL_VAR * +get_lineno (var) + SHELL_VAR *var; +{ + char *p; + int ln; + + ln = executing_line_number (); + p = itos (ln); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +assign_subshell (var, value, unused, key) + SHELL_VAR *var; + char *value; + arrayind_t unused; + char *key; +{ + intmax_t new_value; + + if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) + new_value = 0; + subshell_level = new_value; + return var; +} + +static SHELL_VAR * +get_subshell (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (subshell_level); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bashpid (var) + SHELL_VAR *var; +{ + int pid; + char *p; + + pid = getpid (); + p = itos (pid); + + FREE (value_cell (var)); + VSETATTR (var, att_integer|att_readonly); + var_setvalue (var, p); + return (var); +} + +static SHELL_VAR * +get_bash_command (var) + SHELL_VAR *var; +{ + char *p; + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} + +#if defined (HISTORY) +static SHELL_VAR * +get_histcmd (var) + SHELL_VAR *var; +{ + char *p; + + p = itos (history_number ()); + FREE (value_cell (var)); + var_setvalue (var, p); + return (var); +} +#endif + +#if defined (READLINE) +/* When this function returns, VAR->value points to malloced memory. */ +static SHELL_VAR * +get_comp_wordbreaks (var) + SHELL_VAR *var; +{ + /* If we don't have anything yet, assign a default value. */ + if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0) + enable_hostname_completion (perform_hostname_completion); + + FREE (value_cell (var)); + var_setvalue (var, savestring (rl_completer_word_break_characters)); + + return (var); +} + +/* When this function returns, rl_completer_word_break_characters points to + malloced memory. */ +static SHELL_VAR * +assign_comp_wordbreaks (self, value, unused, key) + SHELL_VAR *self; + char *value; + arrayind_t unused; + char *key; +{ + if (rl_completer_word_break_characters && + rl_completer_word_break_characters != rl_basic_word_break_characters) + free (rl_completer_word_break_characters); + + rl_completer_word_break_characters = savestring (value); + return self; +} +#endif /* READLINE */ + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +assign_dirstack (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + set_dirstack_element (ind, 1, value); + return self; +} + +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (0); + a = array_from_word_list (l); + array_dispose (array_cell (self)); + dispose_words (l); + var_setarray (self, a); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) +/* We don't want to initialize the group set with a call to getgroups() + unless we're asked to, but we only want to do it once. */ +static SHELL_VAR * +get_groupset (self) + SHELL_VAR *self; +{ + register int i; + int ng; + ARRAY *a; + static char **group_set = (char **)NULL; + + if (group_set == 0) + { + group_set = get_group_list (&ng); + a = array_cell (self); + for (i = 0; i < ng; i++) + array_insert (a, i, group_set[i]); + } + return (self); +} + +static SHELL_VAR * +build_hashcmd (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (hashed_filenames->nbuckets); + for (i = 0; i < hashed_filenames->nbuckets; i++) + { + for (item = hash_items (i, hashed_filenames); item; item = item->next) + { + k = savestring (item->key); + v = pathdata(item)->path; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_hashcmd (self) + SHELL_VAR *self; +{ + build_hashcmd (self); + return (self); +} + +static SHELL_VAR * +assign_hashcmd (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + phash_insert (key, value, 0, 0); + return (build_hashcmd (self)); +} + +#if defined (ALIAS) +static SHELL_VAR * +build_aliasvar (self) + SHELL_VAR *self; +{ + HASH_TABLE *h; + int i; + char *k, *v; + BUCKET_CONTENTS *item; + + h = assoc_cell (self); + if (h) + assoc_dispose (h); + + if (aliases == 0 || HASH_ENTRIES (aliases) == 0) + { + var_setvalue (self, (char *)NULL); + return self; + } + + h = assoc_create (aliases->nbuckets); + for (i = 0; i < aliases->nbuckets; i++) + { + for (item = hash_items (i, aliases); item; item = item->next) + { + k = savestring (item->key); + v = ((alias_t *)(item->data))->value; + assoc_insert (h, k, v); + } + } + + var_setvalue (self, (char *)h); + return self; +} + +static SHELL_VAR * +get_aliasvar (self) + SHELL_VAR *self; +{ + build_aliasvar (self); + return (self); +} + +static SHELL_VAR * +assign_aliasvar (self, value, ind, key) + SHELL_VAR *self; + char *value; + arrayind_t ind; + char *key; +{ + add_alias (key, value); + return (build_aliasvar (self)); +} +#endif /* ALIAS */ + +#endif /* ARRAY_VARS */ + +/* If ARRAY_VARS is not defined, this just returns the name of any + currently-executing function. If we have arrays, it's a call stack. */ +static SHELL_VAR * +get_funcname (self) + SHELL_VAR *self; +{ +#if ! defined (ARRAY_VARS) + char *t; + if (variable_context && this_shell_function) + { + FREE (value_cell (self)); + t = savestring (this_shell_function->name); + var_setvalue (self, t); + } +#endif + return (self); +} + +void +make_funcname_visible (on_or_off) + int on_or_off; +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v == 0 || v->dynamic_value == 0) + return; + + if (on_or_off) + VUNSETATTR (v, att_invisible); + else + VSETATTR (v, att_invisible); +} + +static SHELL_VAR * +init_funcname_var () +{ + SHELL_VAR *v; + + v = find_variable ("FUNCNAME"); + if (v) + return v; +#if defined (ARRAY_VARS) + INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); +#else + INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); +#endif + VSETATTR (v, att_invisible|att_noassign); + return v; +} + +static void +initialize_dynamic_variables () +{ + SHELL_VAR *v; + + v = init_seconds_var (); + + INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL); + INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); + + INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); + VSETATTR (v, att_integer); + INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); + VSETATTR (v, att_integer); + + INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign); + VSETATTR (v, att_integer|att_readonly); + +#if defined (HISTORY) + INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); + VSETATTR (v, att_integer); +#endif + +#if defined (READLINE) + INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); +#endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ + +#if defined (ARRAY_VARS) + v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); + +# if defined (DEBUGGER) + v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset); +# endif /* DEBUGGER */ + v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); + + v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); +# if defined (ALIAS) + v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); +# endif +#endif + + v = init_funcname_var (); +} + +/* **************************************************************** */ +/* */ +/* Retrieving variables and values */ +/* */ +/* **************************************************************** */ + +/* How to get a pointer to the shell variable or function named NAME. + HASHED_VARS is a pointer to the hash table containing the list + of interest (either variables or functions). */ + +static SHELL_VAR * +hash_lookup (name, hashed_vars) + const char *name; + HASH_TABLE *hashed_vars; +{ + BUCKET_CONTENTS *bucket; + + bucket = hash_search (name, hashed_vars, 0); + /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that + table. */ + if (bucket) + last_table_searched = hashed_vars; + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); +} + +SHELL_VAR * +var_lookup (name, vcontext) + const char *name; + VAR_CONTEXT *vcontext; +{ + VAR_CONTEXT *vc; + SHELL_VAR *v; + + v = (SHELL_VAR *)NULL; + for (vc = vcontext; vc; vc = vc->down) + if (v = hash_lookup (name, vc->table)) + break; + + return v; +} + +/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, + then also search the temporarily built list of exported variables. + The lookup order is: + temporary_env + shell_variables list +*/ + +SHELL_VAR * +find_variable_internal (name, flags) + const char *name; + int flags; +{ + SHELL_VAR *var; + int search_tempenv, force_tempenv; + VAR_CONTEXT *vc; + + var = (SHELL_VAR *)NULL; + + force_tempenv = (flags & FV_FORCETEMPENV); + + /* If explicitly requested, first look in the temporary environment for + the variable. This allows constructs such as "foo=x eval 'echo $foo'" + to get the `exported' value of $foo. This happens if we are executing + a function or builtin, or if we are looking up a variable in a + "subshell environment". */ + search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); + + if (search_tempenv && temporary_env) + var = hash_lookup (name, temporary_env); + + if (var == 0) + { + if ((flags & FV_SKIPINVISIBLE) == 0) + var = var_lookup (name, shell_variables); + else + { + /* essentially var_lookup expanded inline so we can check for + att_invisible */ + for (vc = shell_variables; vc; vc = vc->down) + { + var = hash_lookup (name, vc->table); + if (var && invisible_p (var)) + var = 0; + if (var) + break; + } + } + } + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up and resolve the chain of nameref variables starting at V all the + way to NULL or non-nameref. */ +SHELL_VAR * +find_variable_nameref (v) + SHELL_VAR *v; +{ + int level, flags; + char *newname; + SHELL_VAR *orig, *oldv; + + level = 0; + orig = v; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + oldv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (newname, flags); + if (v == orig || v == oldv) + { + internal_warning (_("%s: circular name reference"), orig->name); + return ((SHELL_VAR *)0); + } + } + return v; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_variable_last_nameref (name) + const char *name; +{ + SHELL_VAR *v, *nv; + char *newname; + int level, flags; + + nv = v = find_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + nv = v; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (newname, flags); + } + return nv; +} + +/* Resolve the chain of nameref variables for NAME. XXX - could change later */ +SHELL_VAR * +find_global_variable_last_nameref (name) + const char *name; +{ + SHELL_VAR *v, *nv; + char *newname; + int level; + + nv = v = find_global_variable_noref (name); + level = 0; + while (v && nameref_p (v)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)0); /* error message here? */ + newname = nameref_cell (v); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)0); + nv = v; + v = find_global_variable_noref (newname); + } + return nv; +} + +static SHELL_VAR * +find_nameref_at_context (v, vc) + SHELL_VAR *v; + VAR_CONTEXT *vc; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + char *newname; + int level; + + nv = v; + level = 1; + while (nv && nameref_p (nv)) + { + level++; + if (level > NAMEREF_MAX) + return ((SHELL_VAR *)NULL); + newname = nameref_cell (nv); + if (newname == 0 || *newname == '\0') + return ((SHELL_VAR *)NULL); + nv2 = hash_lookup (newname, vc->table); + if (nv2 == 0) + break; + nv = nv2; + } + return nv; +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + if (nameref_p (nv) == 0) + break; + } + return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); +} + +/* Do nameref resolution from the VC, which is the local context for some + function or builtin, `up' the chain to the global variables context. If + NVCP is not NULL, return the variable context where we finally ended the + nameref resolution (so the bind_variable_internal can use the correct + variable context and hash table). */ +static SHELL_VAR * +find_variable_last_nameref_context (v, vc, nvcp) + SHELL_VAR *v; + VAR_CONTEXT *vc; + VAR_CONTEXT **nvcp; +{ + SHELL_VAR *nv, *nv2; + VAR_CONTEXT *nvc; + + /* Look starting at the current context all the way `up' */ + for (nv = v, nvc = vc; nvc; nvc = nvc->down) + { + nv2 = find_nameref_at_context (nv, nvc); + if (nv2 == 0) + continue; + nv = nv2; + if (*nvcp) + *nvcp = nvc; + } + return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); +} + +/* Find a variable, forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_tempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, FV_FORCETEMPENV); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +/* Find a variable, not forcing a search of the temporary environment first */ +SHELL_VAR * +find_variable_notempenv (name) + const char *name; +{ + SHELL_VAR *var; + + var = find_variable_internal (name, 0); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + return (var); +} + +SHELL_VAR * +find_global_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_global_variable_noref (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, global_variables); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +SHELL_VAR * +find_shell_variable (name) + const char *name; +{ + SHELL_VAR *var; + + var = var_lookup (name, shell_variables); + if (var && nameref_p (var)) + var = find_variable_nameref (var); + + if (var == 0) + return ((SHELL_VAR *)NULL); + + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); +} + +/* Look up the variable entry named NAME. Returns the entry or NULL. */ +SHELL_VAR * +find_variable (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found without att_invisible set; return 0 if no non-invisible instances + found. */ +SHELL_VAR * +find_variable_no_invisible (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = FV_SKIPINVISIBLE; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +/* Find the first instance of NAME in the variable context chain; return first + one found even if att_invisible set. */ +SHELL_VAR * +find_variable_for_assignment (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + last_table_searched = 0; + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + if (v && nameref_p (v)) + v = find_variable_nameref (v); + return v; +} + +SHELL_VAR * +find_variable_noref (name) + const char *name; +{ + SHELL_VAR *v; + int flags; + + flags = 0; + if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) + flags |= FV_FORCETEMPENV; + v = find_variable_internal (name, flags); + return v; +} + +/* Look up the function entry whose name matches STRING. + Returns the entry or NULL. */ +SHELL_VAR * +find_function (name) + const char *name; +{ + return (hash_lookup (name, shell_functions)); +} + +/* Find the function definition for the shell function named NAME. Returns + the entry or NULL. */ +FUNCTION_DEF * +find_function_def (name) + const char *name; +{ +#if defined (DEBUGGER) + return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); +#else + return ((FUNCTION_DEF *)0); +#endif +} + +/* Return the value of VAR. VAR is assumed to have been the result of a + lookup without any subscript, if arrays are compiled into the shell. */ +char * +get_variable_value (var) + SHELL_VAR *var; +{ + if (var == 0) + return ((char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); + else if (assoc_p (var)) + return (assoc_reference (assoc_cell (var), "0")); +#endif + else + return (value_cell (var)); +} + +/* Return the string value of a variable. Return NULL if the variable + doesn't exist. Don't cons a new string. This is a potential memory + leak if the variable is found in the temporary environment. Since + functions and variables have separate name spaces, returns NULL if + var_name is a shell function only. */ +char * +get_string_value (var_name) + const char *var_name; +{ + SHELL_VAR *var; + + var = find_variable (var_name); + return ((var) ? get_variable_value (var) : (char *)NULL); +} + +/* This is present for use by the tilde and readline libraries. */ +char * +sh_get_env_value (v) + const char *v; +{ + return get_string_value (v); +} + +/* **************************************************************** */ +/* */ +/* Creating and setting variables */ +/* */ +/* **************************************************************** */ + +/* Set NAME to VALUE if NAME has no value. */ +SHELL_VAR * +set_if_not (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (shell_variables == 0) + create_variable_tables (); + + v = find_variable (name); + if (v == 0) + v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); + return (v); +} + +/* Create a local variable referenced by NAME. */ +SHELL_VAR * +make_local_variable (name) + const char *name; +{ + SHELL_VAR *new_var, *old_var; + VAR_CONTEXT *vc; + int was_tmpvar; + char *tmp_value; + + /* local foo; local foo; is a no-op. */ + old_var = find_variable (name); + if (old_var && local_p (old_var) && old_var->context == variable_context) + return (old_var); + + was_tmpvar = old_var && tempvar_p (old_var); + /* If we're making a local variable in a shell function, the temporary env + has already been merged into the function's variable context stack. We + can assume that a temporary var in the same context appears in the same + VAR_CONTEXT and can safely be returned without creating a new variable + (which results in duplicate names in the same VAR_CONTEXT->table */ + /* We can't just test tmpvar_p because variables in the temporary env given + to a shell function appear in the function's local variable VAR_CONTEXT + but retain their tempvar attribute. We want temporary variables that are + found in temporary_env, hence the test for last_table_searched, which is + set in hash_lookup and only (so far) checked here. */ + if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) + { + VUNSETATTR (old_var, att_invisible); /* XXX */ + return (old_var); + } + if (was_tmpvar) + tmp_value = value_cell (old_var); + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("make_local_variable: no function context at current scope")); + return ((SHELL_VAR *)NULL); + } + else if (vc->table == 0) + vc->table = hash_create (TEMPENV_HASH_BUCKETS); + + /* Since this is called only from the local/declare/typeset code, we can + call builtin_error here without worry (of course, it will also work + for anything that sets this_command_name). Variables with the `noassign' + attribute may not be made local. The test against old_var's context + level is to disallow local copies of readonly global variables (since I + believe that this could be a security hole). Readonly copies of calling + function local variables are OK. */ + if (old_var && (noassign_p (old_var) || + (readonly_p (old_var) && old_var->context == 0))) + { + if (readonly_p (old_var)) + sh_readonly (name); + else if (noassign_p (old_var)) + builtin_error (_("%s: variable may not be assigned value"), name); +#if 0 + /* Let noassign variables through with a warning */ + if (readonly_p (old_var)) +#endif + return ((SHELL_VAR *)NULL); + } + + if (old_var == 0) + new_var = make_new_variable (name, vc->table); + else + { + new_var = make_new_variable (name, vc->table); + + /* If we found this variable in one of the temporary environments, + inherit its value. Watch to see if this causes problems with + things like `x=4 local x'. XXX - see above for temporary env + variables with the same context level as variable_context */ + /* XXX - we should only do this if the variable is not an array. */ + if (was_tmpvar) + var_setvalue (new_var, savestring (tmp_value)); + + new_var->attributes = exported_p (old_var) ? att_exported : 0; + } + + vc->flags |= VC_HASLOCAL; + + new_var->context = variable_context; + VSETATTR (new_var, att_local); + + if (ifsname (name)) + setifs (new_var); + + if (was_tmpvar == 0 && no_invisible_vars == 0) + VSETATTR (new_var, att_invisible); /* XXX */ + return (new_var); +} + +/* Create a new shell variable with name NAME. */ +static SHELL_VAR * +new_shell_variable (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + entry->name = savestring (name); + var_setvalue (entry, (char *)NULL); + CLEAR_EXPORTSTR (entry); + + entry->dynamic_value = (sh_var_value_func_t *)NULL; + entry->assign_func = (sh_var_assign_func_t *)NULL; + + entry->attributes = 0; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibility of changing the + variable context. */ + entry->context = 0; + + return (entry); +} + +/* Create a new shell variable with name NAME and add it to the hash table + TABLE. */ +static SHELL_VAR * +make_new_variable (name, table) + const char *name; + HASH_TABLE *table; +{ + SHELL_VAR *entry; + BUCKET_CONTENTS *elt; + + entry = new_shell_variable (name); + + /* Make sure we have a shell_variables hash table to add to. */ + if (shell_variables == 0) + create_variable_tables (); + + elt = hash_insert (savestring (name), table, HASH_NOSRCH); + elt->data = (PTR_T)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name, global_variables->table); + array = array_create (); + + var_setarray (entry, array); + VSETATTR (entry, att_array); + return entry; +} + +SHELL_VAR * +make_local_array_variable (name, assoc_ok) + char *name; + int assoc_ok; +{ + SHELL_VAR *var; + ARRAY *array; + + var = make_local_variable (name); + if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) + return var; + + array = array_create (); + + dispose_variable_value (var); + var_setarray (var, array); + VSETATTR (var, att_array); + return var; +} + +SHELL_VAR * +make_new_assoc_variable (name) + char *name; +{ + SHELL_VAR *entry; + HASH_TABLE *hash; + + entry = make_new_variable (name, global_variables->table); + hash = assoc_create (0); + + var_setassoc (entry, hash); + VSETATTR (entry, att_assoc); + return entry; +} + +SHELL_VAR * +make_local_assoc_variable (name) + char *name; +{ + SHELL_VAR *var; + HASH_TABLE *hash; + + var = make_local_variable (name); + if (var == 0 || assoc_p (var)) + return var; + + dispose_variable_value (var); + hash = assoc_create (0); + + var_setassoc (var, hash); + VSETATTR (var, att_assoc); + return var; +} +#endif + +char * +make_variable_value (var, value, flags) + SHELL_VAR *var; + char *value; + int flags; +{ + char *retval, *oval; + intmax_t lval, rval; + int expok, olen, op; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp()) and bind_int_variable() are responsible + for turning off the integer flag if they don't want further + evaluation done. */ + if (integer_p (var)) + { + if (flags & ASS_APPEND) + { + oval = value_cell (var); + lval = evalexp (oval, &expok); /* ksh93 seems to do this */ + if (expok == 0) + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + } + rval = evalexp (value, &expok); + if (expok == 0) + { + top_level_cleanup (); + jump_to_top_level (DISCARD); + } + /* This can be fooled if the variable's value changes while evaluating + `rval'. We can change it if we move the evaluation of lval to here. */ + if (flags & ASS_APPEND) + rval += lval; + retval = itos (rval); + } +#if defined (CASEMOD_ATTRS) + else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var)) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + op = capcase_p (var) ? CASE_CAPITALIZE + : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); + oval = sh_modcase (retval, (char *)0, op); + free (retval); + retval = oval; + } +#endif /* CASEMOD_ATTRS */ + else if (value) + { + if (flags & ASS_APPEND) + { + oval = get_variable_value (var); + if (oval == 0) /* paranoia */ + oval = ""; + olen = STRLEN (oval); + retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); + strcpy (retval, oval); + if (value) + strcpy (retval+olen, value); + } + else if (*value) + retval = savestring (value); + else + { + retval = (char *)xmalloc (1); + retval[0] = '\0'; + } + } + else + retval = (char *)NULL; + + return retval; +} + +/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the + temporary environment (but usually is not). */ +static SHELL_VAR * +bind_variable_internal (name, value, table, hflags, aflags) + const char *name; + char *value; + HASH_TABLE *table; + int hflags, aflags; +{ + char *newval; + SHELL_VAR *entry; + + entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); + /* Follow the nameref chain here if this is the global variables table */ + if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) + { + entry = find_global_variable (entry->name); + /* Let's see if we have a nameref referencing a variable that hasn't yet + been created. */ + if (entry == 0) + entry = find_variable_last_nameref (name); /* XXX */ + if (entry == 0) /* just in case */ + return (entry); + } + + /* The first clause handles `declare -n ref; ref=x;' */ + if (entry && invisible_p (entry) && nameref_p (entry)) + goto assign_value; + else if (entry && nameref_p (entry)) + { + newval = nameref_cell (entry); +#if defined (ARRAY_VARS) + /* declare -n foo=x[2] */ + if (valid_array_reference (newval)) + /* XXX - should it be aflags? */ + entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags); + else +#endif + { + entry = make_new_variable (newval, table); + var_setvalue (entry, make_variable_value (entry, value, 0)); + } + } + else if (entry == 0) + { + entry = make_new_variable (name, table); + var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */ + } + else if (entry->assign_func) /* array vars have assign functions now */ + { + INVALIDATE_EXPORTSTR (entry); + newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; + if (assoc_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); + else if (array_p (entry)) + entry = (*(entry->assign_func)) (entry, newval, 0, 0); + else + entry = (*(entry->assign_func)) (entry, newval, -1, 0); + if (newval != value) + free (newval); + return (entry); + } + else + { +assign_value: + if (readonly_p (entry) || noassign_p (entry)) + { + if (readonly_p (entry)) + err_readonly (name); + return (entry); + } + + /* Variables which are bound are visible. */ + VUNSETATTR (entry, att_invisible); + +#if defined (ARRAY_VARS) + if (assoc_p (entry) || array_p (entry)) + newval = make_array_variable_value (entry, 0, "0", value, aflags); + else +#endif + + newval = make_variable_value (entry, value, aflags); /* XXX */ + + /* Invalidate any cached export string */ + INVALIDATE_EXPORTSTR (entry); + +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (assoc_p (entry)) + { + assoc_insert (assoc_cell (entry), savestring ("0"), newval); + free (newval); + } + else if (array_p (entry)) + { + array_insert (array_cell (entry), 0, newval); + free (newval); + } + else +#endif + { + FREE (value_cell (entry)); + var_setvalue (entry, newval); + } + } + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + if (exported_p (entry)) + array_needs_making = 1; + + return (entry); +} + +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. If we have a temporary environment, we bind there + first, then we bind into shell_variables. */ + +SHELL_VAR * +bind_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + int level; + char *newname; + + if (shell_variables == 0) + create_variable_tables (); + + /* If we have a temporary environment, look there first for the variable, + and, if found, modify the value there before modifying it in the + shell_variables table. This allows sourced scripts to modify values + given to them in a temporary environment while modifying the variable + value that the caller sees. */ + if (temporary_env) + bind_tempenv_variable (name, value); + + /* XXX -- handle local variables here. */ + for (vc = shell_variables; vc; vc = vc->down) + { + if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) + { + v = hash_lookup (name, vc->table); + nvc = vc; + if (v && nameref_p (v)) + { + nv = find_variable_nameref_context (v, vc, &nvc); + if (nv == 0) + { + nv = find_variable_last_nameref_context (v, vc, &nvc); + if (nv && nameref_p (nv)) + { + /* If this nameref variable doesn't have a value yet, + set the value. Otherwise, assign using the value as + normal. */ + if (nameref_cell (nv) == 0) + return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); +#if defined (ARRAY_VARS) + else if (valid_array_reference (nameref_cell (nv))) + return (assign_array_element (nameref_cell (nv), value, flags)); + else +#endif + return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); + } + else + v = nv; + } + else + v = nv; + } + if (v) + return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); + } + } + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +SHELL_VAR * +bind_global_variable (name, value, flags) + const char *name; + char *value; + int flags; +{ + SHELL_VAR *v, *nv; + VAR_CONTEXT *vc, *nvc; + int level; + + if (shell_variables == 0) + create_variable_tables (); + + /* bind_variable_internal will handle nameref resolution in this case */ + return (bind_variable_internal (name, value, global_variables->table, 0, flags)); +} + +/* Make VAR, a simple shell variable, have value VALUE. Once assigned a + value, variables are no longer invisible. This is a duplicate of part + of the internals of bind_variable. If the variable is exported, or + all modified variables should be exported, mark the variable for export + and note that the export environment needs to be recreated. */ +SHELL_VAR * +bind_variable_value (var, value, aflags) + SHELL_VAR *var; + char *value; + int aflags; +{ + char *t; + int invis; + + invis = invisible_p (var); + VUNSETATTR (var, att_invisible); + + if (var->assign_func) + { + /* If we're appending, we need the old value, so use + make_variable_value */ + t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; + (*(var->assign_func)) (var, t, -1, 0); + if (t != value && t) + free (t); + } + else + { + t = make_variable_value (var, value, aflags); +#if defined (ARRAY_VARS) + if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0))) +#else + if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0)) +#endif + { + free (t); + if (invis) + VSETATTR (var, att_invisible); /* XXX */ + return ((SHELL_VAR *)NULL); + } + FREE (value_cell (var)); + var_setvalue (var, t); + } + + INVALIDATE_EXPORTSTR (var); + + if (mark_modified_vars) + VSETATTR (var, att_exported); + + if (exported_p (var)) + array_needs_making = 1; + + return (var); +} + +/* Bind/create a shell variable with the name LHS to the RHS. + This creates or modifies a variable such that it is an integer. + + This used to be in expr.c, but it is here so that all of the + variable binding stuff is localized. Since we don't want any + recursive evaluation from bind_variable() (possible without this code, + since bind_variable() calls the evaluator for variables with the integer + attribute set), we temporarily turn off the integer attribute for each + variable we set here, then turn it back on after binding as necessary. */ + +SHELL_VAR * +bind_int_variable (lhs, rhs) + char *lhs, *rhs; +{ + register SHELL_VAR *v; + int isint, isarr, implicitarray; + + isint = isarr = implicitarray = 0; +#if defined (ARRAY_VARS) + if (valid_array_reference (lhs)) + { + isarr = 1; + v = array_variable_part (lhs, (char **)0, (int *)0); + } + else +#endif + v = find_variable (lhs); + + if (v) + { + isint = integer_p (v); + VUNSETATTR (v, att_integer); +#if defined (ARRAY_VARS) + if (array_p (v) && isarr == 0) + implicitarray = 1; +#endif + } + +#if defined (ARRAY_VARS) + if (isarr) + v = assign_array_element (lhs, rhs, 0); + else if (implicitarray) + v = bind_array_variable (lhs, 0, rhs, 0); + else +#endif + v = bind_variable (lhs, rhs, 0); + + if (v && isint) + VSETATTR (v, att_integer); + + VUNSETATTR (v, att_invisible); + + return (v); +} + +SHELL_VAR * +bind_var_to_int (var, val) + char *var; + intmax_t val; +{ + char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; + + p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); + return (bind_int_variable (var, p)); +} + +/* Do a function binding to a variable. You pass the name and + the command to bind to. This conses the name and command. */ +SHELL_VAR * +bind_function (name, value) + const char *name; + COMMAND *value; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry == 0) + { + BUCKET_CONTENTS *elt; + + elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); + entry = new_shell_variable (name); + elt->data = (PTR_T)entry; + } + else + INVALIDATE_EXPORTSTR (entry); + + if (var_isset (entry)) + dispose_command (function_cell (entry)); + + if (value) + var_setfunc (entry, copy_command (value)); + else + var_setfunc (entry, 0); + + VSETATTR (entry, att_function); + + if (mark_modified_vars) + VSETATTR (entry, att_exported); + + VUNSETATTR (entry, att_invisible); /* Just to be sure */ + + if (exported_p (entry)) + array_needs_making = 1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + return (entry); +} + +#if defined (DEBUGGER) +/* Bind a function definition, which includes source file and line number + information in addition to the command, into the FUNCTION_DEF hash table.*/ +void +bind_function_def (name, value) + const char *name; + FUNCTION_DEF *value; +{ + FUNCTION_DEF *entry; + BUCKET_CONTENTS *elt; + COMMAND *cmd; + + entry = find_function_def (name); + if (entry) + { + dispose_function_def_contents (entry); + entry = copy_function_def_contents (value, entry); + } + else + { + cmd = value->command; + value->command = 0; + entry = copy_function_def (value); + value->command = cmd; + + elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); + elt->data = (PTR_T *)entry; + } +} +#endif /* DEBUGGER */ + +/* Add STRING, which is of the form foo=bar, to the temporary environment + HASH_TABLE (temporary_env). The functions in execute_cmd.c are + responsible for moving the main temporary env to one of the other + temporary environments. The expansion code in subst.c calls this. */ +int +assign_in_env (word, flags) + WORD_DESC *word; + int flags; +{ + int offset, aflags; + char *name, *temp, *value; + SHELL_VAR *var; + const char *string; + + string = word->word; + + aflags = 0; + offset = assignment (string, 0); + name = savestring (string); + value = (char *)NULL; + + if (name[offset] == '=') + { + name[offset] = 0; + + /* don't ignore the `+' when assigning temporary environment */ + if (name[offset - 1] == '+') + { + name[offset - 1] = '\0'; + aflags |= ASS_APPEND; + } + + var = find_variable (name); + if (var && (readonly_p (var) || noassign_p (var))) + { + if (readonly_p (var)) + err_readonly (name); + free (name); + return (0); + } + + temp = name + offset + 1; + value = expand_assignment_string_to_string (temp, 0); + + if (var && (aflags & ASS_APPEND)) + { + temp = make_variable_value (var, value, aflags); + FREE (value); + value = temp; + } + } + + if (temporary_env == 0) + temporary_env = hash_create (TEMPENV_HASH_BUCKETS); + + var = hash_lookup (name, temporary_env); + if (var == 0) + var = make_new_variable (name, temporary_env); + else + FREE (value_cell (var)); + + if (value == 0) + { + value = (char *)xmalloc (1); /* like do_assignment_internal */ + value[0] = '\0'; + } + + var_setvalue (var, value); + var->attributes |= (att_exported|att_tempvar); + var->context = variable_context; /* XXX */ + + INVALIDATE_EXPORTSTR (var); + var->exportstr = mk_env_string (name, value); + + array_needs_making = 1; + + if (flags) + stupidly_hack_special_variables (name); + + if (echo_command_at_execute) + /* The Korn shell prints the `+ ' in front of assignment statements, + so we do too. */ + xtrace_print_assignment (name, value, 0, 1); + + free (name); + return 1; +} + +/* **************************************************************** */ +/* */ +/* Copying variables */ +/* */ +/* **************************************************************** */ + +#ifdef INCLUDE_UNUSED +/* Copy VAR to a new data structure and return that structure. */ +SHELL_VAR * +copy_variable (var) + SHELL_VAR *var; +{ + SHELL_VAR *copy = (SHELL_VAR *)NULL; + + if (var) + { + copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + + copy->attributes = var->attributes; + copy->name = savestring (var->name); + + if (function_p (var)) + var_setfunc (copy, copy_command (function_cell (var))); +#if defined (ARRAY_VARS) + else if (array_p (var)) + var_setarray (copy, array_copy (array_cell (var))); + else if (assoc_p (var)) + var_setassoc (copy, assoc_copy (assoc_cell (var))); +#endif + else if (nameref_cell (var)) /* XXX - nameref */ + var_setref (copy, savestring (nameref_cell (var))); + else if (value_cell (var)) /* XXX - nameref */ + var_setvalue (copy, savestring (value_cell (var))); + else + var_setvalue (copy, (char *)NULL); + + copy->dynamic_value = var->dynamic_value; + copy->assign_func = var->assign_func; + + copy->exportstr = COPY_EXPORTSTR (var); + + copy->context = var->context; + } + return (copy); +} +#endif + +/* **************************************************************** */ +/* */ +/* Deleting and unsetting variables */ +/* */ +/* **************************************************************** */ + +/* Dispose of the information attached to VAR. */ +static void +dispose_variable_value (var) + SHELL_VAR *var; +{ + if (function_p (var)) + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + array_dispose (array_cell (var)); + else if (assoc_p (var)) + assoc_dispose (assoc_cell (var)); +#endif + else if (nameref_p (var)) + FREE (nameref_cell (var)); + else + FREE (value_cell (var)); +} + +void +dispose_variable (var) + SHELL_VAR *var; +{ + if (var == 0) + return; + + if (nofree_p (var) == 0) + dispose_variable_value (var); + + FREE_EXPORTSTR (var); + + free (var->name); + + if (exported_p (var)) + array_needs_making = 1; + + free (var); +} + +/* Unset the shell variable referenced by NAME. Unsetting a nameref variable + unsets the variable it resolves to but leaves the nameref alone. */ +int +unbind_variable (name) + const char *name; +{ + SHELL_VAR *v, *nv; + int r; + + v = var_lookup (name, shell_variables); + nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; + + r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); + return r; +} + +/* Unbind NAME, where NAME is assumed to be a nameref variable */ +int +unbind_nameref (name) + const char *name; +{ + SHELL_VAR *v; + + v = var_lookup (name, shell_variables); + if (v && nameref_p (v)) + return makunbound (name, shell_variables); + return 0; +} + +/* Unset the shell function named NAME. */ +int +unbind_func (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *func; + + elt = hash_remove (name, shell_functions, 0); + + if (elt == 0) + return -1; + +#if defined (PROGRAMMABLE_COMPLETION) + set_itemlist_dirty (&it_functions); +#endif + + func = (SHELL_VAR *)elt->data; + if (func) + { + if (exported_p (func)) + array_needs_making++; + dispose_variable (func); + } + + free (elt->key); + free (elt); + + return 0; +} + +#if defined (DEBUGGER) +int +unbind_function_def (name) + const char *name; +{ + BUCKET_CONTENTS *elt; + FUNCTION_DEF *funcdef; + + elt = hash_remove (name, shell_function_defs, 0); + + if (elt == 0) + return -1; + + funcdef = (FUNCTION_DEF *)elt->data; + if (funcdef) + dispose_function_def (funcdef); + + free (elt->key); + free (elt); + + return 0; +} +#endif /* DEBUGGER */ + +int +delete_var (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + free (elt->key); + free (elt); + + dispose_variable (old_var); + return (0); +} + +/* Make the variable associated with NAME go away. HASH_LIST is the + hash table from which this variable should be deleted (either + shell_variables or shell_functions). + Returns non-zero if the variable couldn't be found. */ +int +makunbound (name, vc) + const char *name; + VAR_CONTEXT *vc; +{ + BUCKET_CONTENTS *elt, *new_elt; + SHELL_VAR *old_var; + VAR_CONTEXT *v; + char *t; + + for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) + if (elt = hash_remove (name, v->table, 0)) + break; + + if (elt == 0) + return (-1); + + old_var = (SHELL_VAR *)elt->data; + + if (old_var && exported_p (old_var)) + array_needs_making++; + + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. The function + eventually called by pop_var_context() will clean it up later. This + must be done so that if the variable is subsequently assigned a new + value inside the function, the `local' attribute is still present. + We also need to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && variable_context == old_var->context) + { + if (nofree_p (old_var)) + var_setvalue (old_var, (char *)NULL); +#if defined (ARRAY_VARS) + else if (array_p (old_var)) + array_dispose (array_cell (old_var)); + else if (assoc_p (old_var)) + assoc_dispose (assoc_cell (old_var)); +#endif + else if (nameref_p (old_var)) + FREE (nameref_cell (old_var)); + else + FREE (value_cell (old_var)); + /* Reset the attributes. Preserve the export attribute if the variable + came from a temporary environment. Make sure it stays local, and + make it invisible. */ + old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; + VSETATTR (old_var, att_local); + VSETATTR (old_var, att_invisible); + var_setvalue (old_var, (char *)NULL); + INVALIDATE_EXPORTSTR (old_var); + + new_elt = hash_insert (savestring (old_var->name), v->table, 0); + new_elt->data = (PTR_T)old_var; + stupidly_hack_special_variables (old_var->name); + + free (elt->key); + free (elt); + return (0); + } + + /* Have to save a copy of name here, because it might refer to + old_var->name. If so, stupidly_hack_special_variables will + reference freed memory. */ + t = savestring (name); + + free (elt->key); + free (elt); + + dispose_variable (old_var); + stupidly_hack_special_variables (t); + free (t); + + return (0); +} + +/* Get rid of all of the variables in the current context. */ +void +kill_all_local_variables () +{ + VAR_CONTEXT *vc; + + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + if (vc == 0) + return; /* XXX */ + + if (vc->table && vc_haslocals (vc)) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + vc->table = (HASH_TABLE *)NULL; +} + +static void +free_variable_hash_data (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + dispose_variable (var); +} + +/* Delete the entire contents of the hash table. */ +void +delete_all_variables (hashed_vars) + HASH_TABLE *hashed_vars; +{ + hash_flush (hashed_vars, free_variable_hash_data); +} + +/* **************************************************************** */ +/* */ +/* Setting variable attributes */ +/* */ +/* **************************************************************** */ + +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, "", 0); \ + if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. + If NAME does not exist yet, create it. */ +void +set_var_read_only (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + VSETATTR (entry, att_readonly); +} + +#ifdef INCLUDE_UNUSED +/* Make the function associated with NAME be readonly. + If NAME does not exist, we just punt, like auto_export code below. */ +void +set_func_read_only (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + VSETATTR (entry, att_readonly); +} + +/* Make the variable associated with NAME be auto-exported. + If NAME does not exist yet, create it. */ +void +set_var_auto_export (name) + char *name; +{ + SHELL_VAR *entry; + + FIND_OR_MAKE_VARIABLE (name, entry); + set_auto_export (entry); +} + +/* Make the function associated with NAME be auto-exported. */ +void +set_func_auto_export (name) + const char *name; +{ + SHELL_VAR *entry; + + entry = find_function (name); + if (entry) + set_auto_export (entry); +} +#endif + +/* **************************************************************** */ +/* */ +/* Creating lists of variables */ +/* */ +/* **************************************************************** */ + +static VARLIST * +vlist_alloc (nentries) + int nentries; +{ + VARLIST *vlist; + + vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); + vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); + vlist->list_size = nentries; + vlist->list_len = 0; + vlist->list[0] = (SHELL_VAR *)NULL; + + return vlist; +} + +static VARLIST * +vlist_realloc (vlist, n) + VARLIST *vlist; + int n; +{ + if (vlist == 0) + return (vlist = vlist_alloc (n)); + if (n > vlist->list_size) + { + vlist->list_size = n; + vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); + } + return vlist; +} + +static void +vlist_add (vlist, var, flags) + VARLIST *vlist; + SHELL_VAR *var; + int flags; +{ + register int i; + + for (i = 0; i < vlist->list_len; i++) + if (STREQ (var->name, vlist->list[i]->name)) + break; + if (i < vlist->list_len) + return; + + if (i >= vlist->list_size) + vlist = vlist_realloc (vlist, vlist->list_size + 16); + + vlist->list[vlist->list_len++] = var; + vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; +} + +/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the + variables for which FUNCTION returns a non-zero value. A NULL value + for FUNCTION means to use all variables. */ +SHELL_VAR ** +map_over (function, vc) + sh_var_map_func_t *function; + VAR_CONTEXT *vc; +{ + VAR_CONTEXT *v; + VARLIST *vlist; + SHELL_VAR **ret; + int nentries; + + for (nentries = 0, v = vc; v; v = v->down) + nentries += HASH_ENTRIES (v->table); + + if (nentries == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (nentries); + + for (v = vc; v; v = v->down) + flatten (v->table, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +SHELL_VAR ** +map_over_funcs (function) + sh_var_map_func_t *function; +{ + VARLIST *vlist; + SHELL_VAR **ret; + + if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) + return ((SHELL_VAR **)NULL); + + vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); + + flatten (shell_functions, function, vlist, 0); + + ret = vlist->list; + free (vlist); + return ret; +} + +/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those + elements for which FUNC succeeds to VLIST->list. FLAGS is reserved + for future use. Only unique names are added to VLIST. If FUNC is + NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is + NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST + and FUNC are both NULL, nothing happens. */ +static void +flatten (var_hash_table, func, vlist, flags) + HASH_TABLE *var_hash_table; + sh_var_map_func_t *func; + VARLIST *vlist; + int flags; +{ + register int i; + register BUCKET_CONTENTS *tlist; + int r; + SHELL_VAR *var; + + if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) + return; + + for (i = 0; i < var_hash_table->nbuckets; i++) + { + for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) + { + var = (SHELL_VAR *)tlist->data; + + r = func ? (*func) (var) : 1; + if (r && vlist) + vlist_add (vlist, var, flags); + } + } +} + +void +sort_variables (array) + SHELL_VAR **array; +{ + qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); +} + +static int +qsort_var_comp (var1, var2) + SHELL_VAR **var1, **var2; +{ + int result; + + if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) + result = strcmp ((*var1)->name, (*var2)->name); + + return (result); +} + +/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +vapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over (func, shell_variables); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for + which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ +static SHELL_VAR ** +fapply (func) + sh_var_map_func_t *func; +{ + SHELL_VAR **list; + + list = map_over_funcs (func); + if (list /* && posixly_correct */) + sort_variables (list); + return (list); +} + +/* Create a NULL terminated array of all the shell variables. */ +SHELL_VAR ** +all_shell_variables () +{ + return (vapply ((sh_var_map_func_t *)NULL)); +} + +/* Create a NULL terminated array of all the shell functions. */ +SHELL_VAR ** +all_shell_functions () +{ + return (fapply ((sh_var_map_func_t *)NULL)); +} + +static int +visible_var (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0); +} + +SHELL_VAR ** +all_visible_functions () +{ + return (fapply (visible_var)); +} + +SHELL_VAR ** +all_visible_variables () +{ + return (vapply (visible_var)); +} + +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ +static int +visible_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && exported_p (var)); +} + +/* Candidate variables for the export environment are either valid variables + with the export attribute or invalid variables inherited from the initial + environment and simply passed through. */ +static int +export_environment_candidate (var) + SHELL_VAR *var; +{ + return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); +} + +/* Return non-zero if VAR is a local variable in the current context and + is exported. */ +static int +local_and_exported (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); +} + +SHELL_VAR ** +all_exported_variables () +{ + return (vapply (visible_and_exported)); +} + +SHELL_VAR ** +local_exported_variables () +{ + return (vapply (local_and_exported)); +} + +static int +variable_in_context (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); +} + +SHELL_VAR ** +all_local_variables () +{ + VARLIST *vlist; + SHELL_VAR **ret; + VAR_CONTEXT *vc; + + vc = shell_variables; + for (vc = shell_variables; vc; vc = vc->down) + if (vc_isfuncenv (vc) && vc->scope == variable_context) + break; + + if (vc == 0) + { + internal_error (_("all_local_variables: no function context at current scope")); + return (SHELL_VAR **)NULL; + } + if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) + return (SHELL_VAR **)NULL; + + vlist = vlist_alloc (HASH_ENTRIES (vc->table)); + + flatten (vc->table, variable_in_context, vlist, 0); + + ret = vlist->list; + free (vlist); + if (ret) + sort_variables (ret); + return ret; +} + +#if defined (ARRAY_VARS) +/* Return non-zero if the variable VAR is visible and an array. */ +static int +visible_array_vars (var) + SHELL_VAR *var; +{ + return (invisible_p (var) == 0 && array_p (var)); +} + +SHELL_VAR ** +all_array_variables () +{ + return (vapply (visible_array_vars)); +} +#endif /* ARRAY_VARS */ + +char ** +all_variables_matching_prefix (prefix) + const char *prefix; +{ + SHELL_VAR **varlist; + char **rlist; + int vind, rind, plen; + + plen = STRLEN (prefix); + varlist = all_visible_variables (); + for (vind = 0; varlist && varlist[vind]; vind++) + ; + if (varlist == 0 || vind == 0) + return ((char **)NULL); + rlist = strvec_create (vind + 1); + for (vind = rind = 0; varlist[vind]; vind++) + { + if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) + rlist[rind++] = savestring (varlist[vind]->name); + } + rlist[rind] = (char *)0; + free (varlist); + + return rlist; +} + +/* **************************************************************** */ +/* */ +/* Managing temporary variable scopes */ +/* */ +/* **************************************************************** */ + +/* Make variable NAME have VALUE in the temporary environment. */ +static SHELL_VAR * +bind_tempenv_variable (name, value) + const char *name; + char *value; +{ + SHELL_VAR *var; + + var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; + + if (var) + { + FREE (value_cell (var)); + var_setvalue (var, savestring (value)); + INVALIDATE_EXPORTSTR (var); + } + + return (var); +} + +/* Find a variable in the temporary environment that is named NAME. + Return the SHELL_VAR *, or NULL if not found. */ +SHELL_VAR * +find_tempenv_variable (name) + const char *name; +{ + return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); +} + +char **tempvar_list; +int tvlist_ind; + +/* Push the variable described by (SHELL_VAR *)DATA down to the next + variable context from the temporary environment. */ +static void +push_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = shell_variables->table; + if (binding_table == 0) + { + if (shell_variables == global_variables) + /* shouldn't happen */ + binding_table = shell_variables->table = global_variables->table = hash_create (0); + else + binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); + } + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0); + + /* XXX - should we set the context here? It shouldn't matter because of how + assign_in_env works, but might want to check. */ + if (binding_table == global_variables->table) /* XXX */ + var->attributes &= ~(att_tempvar|att_propagate); + else + { + var->attributes |= att_propagate; + if (binding_table == shell_variables->table) + shell_variables->flags |= VC_HASTMPVAR; + } + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + +static void +propagate_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var; + + var = (SHELL_VAR *)data; + if (tempvar_p (var) && (var->attributes & att_propagate)) + push_temp_var (data); + else + { + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + dispose_variable (var); + } +} + +/* Free the storage used in the hash table for temporary + environment variables. PUSHF is a function to be called + to free each hash table entry. It takes care of pushing variables + to previous scopes if appropriate. PUSHF stores names of variables + that require special handling (e.g., IFS) on tempvar_list, so this + function can call stupidly_hack_special_variables on all the + variables in the list when the temporary hash table is destroyed. */ +static void +dispose_temporary_env (pushf) + sh_free_func_t *pushf; +{ + int i; + + tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); + tempvar_list[tvlist_ind = 0] = 0; + + hash_flush (temporary_env, pushf); + hash_dispose (temporary_env); + temporary_env = (HASH_TABLE *)NULL; + + tempvar_list[tvlist_ind] = 0; + + array_needs_making = 1; + +#if 0 + sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */ +#endif + for (i = 0; i < tvlist_ind; i++) + stupidly_hack_special_variables (tempvar_list[i]); + + strvec_dispose (tempvar_list); + tempvar_list = 0; + tvlist_ind = 0; +} + +void +dispose_used_env_vars () +{ + if (temporary_env) + { + dispose_temporary_env (propagate_temp_var); + maybe_make_export_env (); + } +} + +/* Take all of the shell variables in the temporary environment HASH_TABLE + and make shell variables from them at the current variable context. */ +void +merge_temporary_env () +{ + if (temporary_env) + dispose_temporary_env (push_temp_var); +} + +/* **************************************************************** */ +/* */ +/* Creating and manipulating the environment */ +/* */ +/* **************************************************************** */ + +static inline char * +mk_env_string (name, value) + const char *name, *value; +{ + int name_len, value_len; + char *p; + + name_len = strlen (name); + value_len = STRLEN (value); + p = (char *)xmalloc (2 + name_len + value_len); + strcpy (p, name); + p[name_len] = '='; + if (value && *value) + strcpy (p + name_len + 1, value); + else + p[name_len + 1] = '\0'; + return (p); +} + +#ifdef DEBUG +/* Debugging */ +static int +valid_exportstr (v) + SHELL_VAR *v; +{ + char *s; + + s = v->exportstr; + if (s == 0) + { + internal_error (_("%s has null exportstr"), v->name); + return (0); + } + if (legal_variable_starter ((unsigned char)*s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + for (s = v->exportstr + 1; s && *s; s++) + { + if (*s == '=') + break; + if (legal_variable_char ((unsigned char)*s) == 0) + { + internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); + return (0); + } + } + if (*s != '=') + { + internal_error (_("no `=' in exportstr for %s"), v->name); + return (0); + } + return (1); +} +#endif + +static char ** +make_env_array_from_var_list (vars) + SHELL_VAR **vars; +{ + register int i, list_index; + register SHELL_VAR *var; + char **list, *value; + + list = strvec_create ((1 + strvec_len ((char **)vars))); + +#define USE_EXPORTSTR (value == var->exportstr) + + for (i = 0, list_index = 0; var = vars[i]; i++) + { +#if defined (__CYGWIN__) + /* We don't use the exportstr stuff on Cygwin at all. */ + INVALIDATE_EXPORTSTR (var); +#endif + if (var->exportstr) + value = var->exportstr; + else if (function_p (var)) + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if ARRAY_EXPORT + value = array_to_assignment_string (array_cell (var)); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif /* ARRAY_EXPORT */ + else if (assoc_p (var)) +# if 0 + value = assoc_to_assignment_string (assoc_cell (var)); +# else + continue; /* XXX associative array vars cannot yet be exported */ +# endif +#endif + else + value = value_cell (var); + + if (value) + { + /* Gee, I'd like to get away with not using savestring() if we're + using the cached exportstr... */ + list[list_index] = USE_EXPORTSTR ? savestring (value) + : mk_env_string (var->name, value); + + if (USE_EXPORTSTR == 0) + SAVE_EXPORTSTR (var, list[list_index]); + + list_index++; +#undef USE_EXPORTSTR + +#if 0 /* not yet */ +#if defined (ARRAY_VARS) + if (array_p (var) || assoc_p (var)) + free (value); +#endif +#endif + } + } + + list[list_index] = (char *)NULL; + return (list); +} + +/* Make an array of assignment statements from the hash table + HASHED_VARS which contains SHELL_VARs. Only visible, exported + variables are eligible. */ +static char ** +make_var_export_array (vcxt) + VAR_CONTEXT *vcxt; +{ + char **list; + SHELL_VAR **vars; + +#if 0 + vars = map_over (visible_and_exported, vcxt); +#else + vars = map_over (export_environment_candidate, vcxt); +#endif + + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +static char ** +make_func_export_array () +{ + char **list; + SHELL_VAR **vars; + + vars = map_over_funcs (visible_and_exported); + if (vars == 0) + return (char **)NULL; + + list = make_env_array_from_var_list (vars); + + free (vars); + return (list); +} + +/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ +#define add_to_export_env(envstr,do_alloc) \ +do \ + { \ + if (export_env_index >= (export_env_size - 1)) \ + { \ + export_env_size += 16; \ + export_env = strvec_resize (export_env, export_env_size); \ + environ = export_env; \ + } \ + export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ + export_env[export_env_index] = (char *)NULL; \ + } while (0) + +/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the + array with the same left-hand side. Return the new EXPORT_ENV. */ +char ** +add_or_supercede_exported_var (assign, do_alloc) + char *assign; + int do_alloc; +{ + register int i; + int equal_offset; + + equal_offset = assignment (assign, 0); + if (equal_offset == 0) + return (export_env); + + /* If this is a function, then only supersede the function definition. + We do this by including the `=() {' in the comparison, like + initialize_shell_variables does. */ + if (assign[equal_offset + 1] == '(' && + strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ + equal_offset += 4; + + for (i = 0; i < export_env_index; i++) + { + if (STREQN (assign, export_env[i], equal_offset + 1)) + { + free (export_env[i]); + export_env[i] = do_alloc ? savestring (assign) : assign; + return (export_env); + } + } + add_to_export_env (assign, do_alloc); + return (export_env); +} + +static void +add_temp_array_to_env (temp_array, do_alloc, do_supercede) + char **temp_array; + int do_alloc, do_supercede; +{ + register int i; + + if (temp_array == 0) + return; + + for (i = 0; temp_array[i]; i++) + { + if (do_supercede) + export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); + else + add_to_export_env (temp_array[i], do_alloc); + } + + free (temp_array); +} + +/* Make the environment array for the command about to be executed, if the + array needs making. Otherwise, do nothing. If a shell action could + change the array that commands receive for their environment, then the + code should `array_needs_making++'. + + The order to add to the array is: + temporary_env + list of var contexts whose head is shell_variables + shell_functions + + This is the shell variable lookup order. We add only new variable + names at each step, which allows local variables and variables in + the temporary environments to shadow variables in the global (or + any previous) scope. +*/ + +static int +n_shell_variables () +{ + VAR_CONTEXT *vc; + int n; + + for (n = 0, vc = shell_variables; vc; vc = vc->down) + n += HASH_ENTRIES (vc->table); + return n; +} + +int +chkexport (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v && exported_p (v)) + { + array_needs_making = 1; + maybe_make_export_env (); + return 1; + } + return 0; +} + +void +maybe_make_export_env () +{ + register char **temp_array; + int new_size; + VAR_CONTEXT *tcxt; + + if (array_needs_making) + { + if (export_env) + strvec_flush (export_env); + + /* Make a guess based on how many shell variables and functions we + have. Since there will always be array variables, and array + variables are not (yet) exported, this will always be big enough + for the exported variables and functions. */ + new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + + HASH_ENTRIES (temporary_env); + if (new_size > export_env_size) + { + export_env_size = new_size; + export_env = strvec_resize (export_env, export_env_size); + environ = export_env; + } + export_env[export_env_index = 0] = (char *)NULL; + + /* Make a dummy variable context from the temporary_env, stick it on + the front of shell_variables, call make_var_export_array on the + whole thing to flatten it, and convert the list of SHELL_VAR *s + to the form needed by the environment. */ + if (temporary_env) + { + tcxt = new_var_context ((char *)NULL, 0); + tcxt->table = temporary_env; + tcxt->down = shell_variables; + } + else + tcxt = shell_variables; + + temp_array = make_var_export_array (tcxt); + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + if (tcxt != shell_variables) + free (tcxt); + +#if defined (RESTRICTED_SHELL) + /* Restricted shells may not export shell functions. */ + temp_array = restricted ? (char **)0 : make_func_export_array (); +#else + temp_array = make_func_export_array (); +#endif + if (temp_array) + add_temp_array_to_env (temp_array, 0, 0); + + array_needs_making = 0; + } +} + +/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so + we will need to remake the exported environment every time we + change directories. `_' is always put into the environment for + every external command, so without special treatment it will always + cause the environment to be remade. + + If there is no other reason to make the exported environment, we can + just update the variables in place and mark the exported environment + as no longer needing a remake. */ +void +update_export_env_inplace (env_prefix, preflen, value) + char *env_prefix; + int preflen; + char *value; +{ + char *evar; + + evar = (char *)xmalloc (STRLEN (value) + preflen + 1); + strcpy (evar, env_prefix); + if (value) + strcpy (evar + preflen, value); + export_env = add_or_supercede_exported_var (evar, 0); +} + +/* We always put _ in the environment as the name of this command. */ +void +put_command_name_into_env (command_name) + char *command_name; +{ + update_export_env_inplace ("_=", 2, command_name); +} + +/* **************************************************************** */ +/* */ +/* Managing variable contexts */ +/* */ +/* **************************************************************** */ + +/* Allocate and return a new variable context with NAME and FLAGS. + NAME can be NULL. */ + +VAR_CONTEXT * +new_var_context (name, flags) + char *name; + int flags; +{ + VAR_CONTEXT *vc; + + vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); + vc->name = name ? savestring (name) : (char *)NULL; + vc->scope = variable_context; + vc->flags = flags; + + vc->up = vc->down = (VAR_CONTEXT *)NULL; + vc->table = (HASH_TABLE *)NULL; + + return vc; +} + +/* Free a variable context and its data, including the hash table. Dispose + all of the variables. */ +void +dispose_var_context (vc) + VAR_CONTEXT *vc; +{ + FREE (vc->name); + + if (vc->table) + { + delete_all_variables (vc->table); + hash_dispose (vc->table); + } + + free (vc); +} + +/* Set VAR's scope level to the current variable context. */ +static int +set_context (var) + SHELL_VAR *var; +{ + return (var->context = variable_context); +} + +/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of + temporary variables, and push it onto shell_variables. This is + for shell functions. */ +VAR_CONTEXT * +push_var_context (name, flags, tempvars) + char *name; + int flags; + HASH_TABLE *tempvars; +{ + VAR_CONTEXT *vc; + + vc = new_var_context (name, flags); + vc->table = tempvars; + if (tempvars) + { + /* Have to do this because the temp environment was created before + variable_context was incremented. */ + flatten (tempvars, set_context, (VARLIST *)NULL, 0); + vc->flags |= VC_HASTMPVAR; + } + vc->down = shell_variables; + shell_variables->up = vc; + + return (shell_variables = vc); +} + +static void +push_func_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate))) + { + /* Make sure we have a hash table to store the variable in while it is + being propagated down to the global variables table. Create one if + we have to */ + if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) + shell_variables->table = hash_create (0); + /* XXX - should we set v->context here? */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~(att_tempvar|att_propagate); + else + shell_variables->flags |= VC_HASTMPVAR; + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +/* Pop the top context off of VCXT and dispose of it, returning the rest of + the stack. */ +void +pop_var_context () +{ + VAR_CONTEXT *ret, *vcxt; + + vcxt = shell_variables; + if (vc_isfuncenv (vcxt) == 0) + { + internal_error (_("pop_var_context: head of shell_variables not a function context")); + return; + } + + if (ret = vcxt->down) + { + ret->up = (VAR_CONTEXT *)NULL; + shell_variables = ret; + if (vcxt->table) + hash_flush (vcxt->table, push_func_var); + dispose_var_context (vcxt); + } + else + internal_error (_("pop_var_context: no global_variables context")); +} + +/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and + all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ +void +delete_all_contexts (vcxt) + VAR_CONTEXT *vcxt; +{ + VAR_CONTEXT *v, *t; + + for (v = vcxt; v != global_variables; v = t) + { + t = v->down; + dispose_var_context (v); + } + + delete_all_variables (global_variables->table); + shell_variables = global_variables; +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping temporary variable scopes */ +/* */ +/* **************************************************************** */ + +VAR_CONTEXT * +push_scope (flags, tmpvars) + int flags; + HASH_TABLE *tmpvars; +{ + return (push_var_context ((char *)NULL, flags, tmpvars)); +} + +static void +push_exported_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + + var = (SHELL_VAR *)data; + + /* If a temp var had its export attribute set, or it's marked to be + propagated, bind it in the previous scope before disposing it. */ + /* XXX - This isn't exactly right, because all tempenv variables have the + export attribute set. */ +#if 0 + if (exported_p (var) || (var->attributes & att_propagate)) +#else + if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) +#endif + { + var->attributes &= ~att_tempvar; /* XXX */ + v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); + if (shell_variables == global_variables) + var->attributes &= ~att_propagate; + v->attributes |= var->attributes; + } + else + stupidly_hack_special_variables (var->name); /* XXX */ + + dispose_variable (var); +} + +void +pop_scope (is_special) + int is_special; +{ + VAR_CONTEXT *vcxt, *ret; + + vcxt = shell_variables; + if (vc_istempscope (vcxt) == 0) + { + internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); + return; + } + + ret = vcxt->down; + if (ret) + ret->up = (VAR_CONTEXT *)NULL; + + shell_variables = ret; + + /* Now we can take care of merging variables in VCXT into set of scopes + whose head is RET (shell_variables). */ + FREE (vcxt->name); + if (vcxt->table) + { + if (is_special) + hash_flush (vcxt->table, push_func_var); + else + hash_flush (vcxt->table, push_exported_var); + hash_dispose (vcxt->table); + } + free (vcxt); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* **************************************************************** */ +/* */ +/* Pushing and Popping function contexts */ +/* */ +/* **************************************************************** */ + +static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; + +/* XXX - we might want to consider pushing and popping the `getopts' state + when we modify the positional parameters. */ +void +push_context (name, is_subshell, tempvars) + char *name; /* function name */ + int is_subshell; + HASH_TABLE *tempvars; +{ + if (is_subshell == 0) + push_dollar_vars (); + variable_context++; + push_var_context (name, VC_FUNCENV, tempvars); +} + +/* Only called when subshell == 0, so we don't need to check, and can + unconditionally pop the dollar vars off the stack. */ +void +pop_context () +{ + pop_dollar_vars (); + variable_context--; + pop_var_context (); + + sv_ifs ("IFS"); /* XXX here for now */ +} + +/* Save the existing positional parameters on a stack. */ +void +push_dollar_vars () +{ + if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) + { + dollar_arg_stack = (WORD_LIST **) + xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) + * sizeof (WORD_LIST *)); + } + dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args (); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; +} + +/* Restore the positional parameters from our stack. */ +void +pop_dollar_vars () +{ + if (!dollar_arg_stack || dollar_arg_stack_index == 0) + return; + + remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); + dispose_words (dollar_arg_stack[dollar_arg_stack_index]); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; + set_dollar_vars_unchanged (); +} + +void +dispose_saved_dollar_vars () +{ + if (!dollar_arg_stack || dollar_arg_stack_index == 0) + return; + + dispose_words (dollar_arg_stack[dollar_arg_stack_index]); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; +} + +/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */ + +void +push_args (list) + WORD_LIST *list; +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bash_argv_v, *bash_argc_v; + ARRAY *bash_argv_a, *bash_argc_a; + WORD_LIST *l; + arrayind_t i; + char *t; + + GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); + GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); + + for (l = list, i = 0; l; l = l->next, i++) + array_push (bash_argv_a, l->word->word); + + t = itos (i); + array_push (bash_argc_a, t); + free (t); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC + array and use that value as the count of elements to remove from + BASH_ARGV. */ +void +pop_args () +{ +#if defined (ARRAY_VARS) && defined (DEBUGGER) + SHELL_VAR *bash_argv_v, *bash_argc_v; + ARRAY *bash_argv_a, *bash_argc_a; + ARRAY_ELEMENT *ce; + intmax_t i; + + GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); + GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); + + ce = array_shift (bash_argc_a, 1, 0); + if (ce == 0 || legal_number (element_value (ce), &i) == 0) + i = 0; + + for ( ; i > 0; i--) + array_pop (bash_argv_a); + array_dispose_element (ce); +#endif /* ARRAY_VARS && DEBUGGER */ +} + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ +extern int eof_encountered, eof_encountered_limit, ignoreeof; + +#if defined (READLINE) +extern int hostname_list_initialized; +#endif + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + switch statement, but by the end of this file, I am sick of switch + statements. */ + +#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 + +/* This table will be sorted with qsort() the first time it's accessed. */ +struct name_and_function { + char *name; + sh_sv_func_t *function; +}; + +static struct name_and_function special_vars[] = { + { "BASH_COMPAT", sv_shcompat }, + { "BASH_XTRACEFD", sv_xtracefd }, + +#if defined (JOB_CONTROL) + { "CHILD_MAX", sv_childmax }, +#endif + +#if defined (READLINE) +# if defined (STRICT_POSIX) + { "COLUMNS", sv_winsize }, +# endif + { "COMP_WORDBREAKS", sv_comp_wordbreaks }, +#endif + + { "FUNCNEST", sv_funcnest }, + + { "GLOBIGNORE", sv_globignore }, + +#if defined (HISTORY) + { "HISTCONTROL", sv_history_control }, + { "HISTFILESIZE", sv_histsize }, + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTTIMEFORMAT", sv_histtimefmt }, +#endif + +#if defined (__CYGWIN__) + { "HOME", sv_home }, +#endif + +#if defined (READLINE) + { "HOSTFILE", sv_hostfile }, +#endif + + { "IFS", sv_ifs }, + { "IGNOREEOF", sv_ignoreeof }, + + { "LANG", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LC_NUMERIC", sv_locale }, + { "LC_TIME", sv_locale }, + +#if defined (READLINE) && defined (STRICT_POSIX) + { "LINES", sv_winsize }, +#endif + + { "MAIL", sv_mail }, + { "MAILCHECK", sv_mail }, + { "MAILPATH", sv_mail }, + + { "OPTERR", sv_opterr }, + { "OPTIND", sv_optind }, + + { "PATH", sv_path }, + { "POSIXLY_CORRECT", sv_strict_posix }, + +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, +#endif /* READLINE */ + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +#if defined (HAVE_TZSET) + { "TZ", sv_tz }, +#endif + +#if defined (HISTORY) && defined (BANG_HISTORY) + { "histchars", sv_histchars }, +#endif /* HISTORY && BANG_HISTORY */ + + { "ignoreeof", sv_ignoreeof }, + + { (char *)0, (sh_sv_func_t *)0 } +}; + +#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) + +static int +sv_compare (sv1, sv2) + struct name_and_function *sv1, *sv2; +{ + int r; + + if ((r = sv1->name[0] - sv2->name[0]) == 0) + r = strcmp (sv1->name, sv2->name); + return r; +} + +static inline int +find_special_var (name) + const char *name; +{ + register int i, r; + + for (i = 0; special_vars[i].name; i++) + { + r = special_vars[i].name[0] - name[0]; + if (r == 0) + r = strcmp (special_vars[i].name, name); + if (r == 0) + return i; + else if (r > 0) + /* Can't match any of rest of elements in sorted list. Take this out + if it causes problems in certain environments. */ + break; + } + return -1; +} + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + static int sv_sorted = 0; + int i; + + if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ + { + qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), + (QSFUNC *)sv_compare); + sv_sorted = 1; + } + + i = find_special_var (name); + if (i != -1) + (*(special_vars[i].function)) (name); +} + +/* Special variables that need hooks to be run when they are unset as part + of shell reinitialization should have their sv_ functions run here. */ +void +reinit_special_variables () +{ +#if defined (READLINE) + sv_comp_wordbreaks ("COMP_WORDBREAKS"); +#endif + sv_globignore ("GLOBIGNORE"); + sv_opterr ("OPTERR"); +} + +void +sv_ifs (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable ("IFS"); + setifs (v); +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + phash_flush (); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +void +sv_funcnest (name) + char *name; +{ + SHELL_VAR *v; + intmax_t num; + + v = find_variable (name); + if (v == 0) + funcnest_max = 0; + else if (legal_number (value_cell (v), &num) == 0) + funcnest_max = 0; + else + funcnest_max = num; +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + if (privileged_mode == 0) + setup_glob_ignore (name); +} + +#if defined (READLINE) +void +sv_comp_wordbreaks (name) + char *name; +{ + SHELL_VAR *sv; + + sv = find_variable (name); + if (sv == 0) + reset_completer_word_break_chars (); +} + +/* What to do just after one of the TERMxxx variables has changed. + If we are an interactive shell, then try to reset the terminal + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && no_line_editing == 0) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostfile (name) + char *name; +{ + SHELL_VAR *v; + + v = find_variable (name); + if (v == 0) + clear_hostname_list (); + else + hostname_list_initialized = 0; +} + +#if defined (STRICT_POSIX) +/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values + found in the initial environment) to override the terminal size reported by + the kernel. */ +void +sv_winsize (name) + char *name; +{ + SHELL_VAR *v; + intmax_t xd; + int d; + + if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) + return; + + v = find_variable (name); + if (v == 0 || var_isnull (v)) + rl_reset_screen_size (); + else + { + if (legal_number (value_cell (v), &xd) == 0) + return; + winsize_assignment = 1; + d = xd; /* truncate */ + if (name[0] == 'L') /* LINES */ + rl_set_screen_size (d, -1); + else /* COLUMNS */ + rl_set_screen_size (-1, d); + winsize_assignment = 0; + } +} +#endif /* STRICT_POSIX */ +#endif /* READLINE */ + +/* Update the value of HOME in the export environment so tilde expansion will + work on cygwin. */ +#if defined (__CYGWIN__) +sv_home (name) + char *name; +{ + array_needs_making = 1; + maybe_make_export_env (); +} +#endif + +#if defined (HISTORY) +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle + the history. Otherwise, if there is NO value for this variable, + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ +void +sv_histsize (name) + char *name; +{ + char *temp; + intmax_t num; + int hmax; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + hmax = num; + if (hmax < 0 && name[4] == 'S') + unstifle_history (); /* unstifle history if HISTSIZE < 0 */ + else if (name[4] == 'S') + { + stifle_history (hmax); + hmax = where_history (); + if (history_lines_this_session > hmax) + history_lines_this_session = hmax; + } + else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ + { + history_truncate_file (get_string_value ("HISTFILE"), hmax); + if (hmax <= history_lines_in_file) + history_lines_in_file = hmax; + } + } + } + else if (name[4] == 'S') + unstifle_history (); +} + +/* What to do after the HISTIGNORE variable changes. */ +void +sv_histignore (name) + char *name; +{ + setup_history_ignore (name); +} + +/* What to do after the HISTCONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp; + char *val; + int tptr; + + history_control = 0; + temp = get_string_value (name); + + if (temp == 0 || *temp == 0) + return; + + tptr = 0; + while (val = extract_colon_unit (temp, &tptr)) + { + if (STREQ (val, "ignorespace")) + history_control |= HC_IGNSPACE; + else if (STREQ (val, "ignoredups")) + history_control |= HC_IGNDUPS; + else if (STREQ (val, "ignoreboth")) + history_control |= HC_IGNBOTH; + else if (STREQ (val, "erasedups")) + history_control |= HC_ERASEDUPS; + + free (val); + } +} + +#if defined (BANG_HISTORY) +/* Setting/unsetting of the history expansion character. */ +void +sv_histchars (name) + char *name; +{ + char *temp; + + temp = get_string_value (name); + if (temp) + { + history_expansion_char = *temp; + if (temp[0] && temp[1]) + { + history_subst_char = temp[1]; + if (temp[2]) + history_comment_char = temp[2]; + } + } + else + { + history_expansion_char = '!'; + history_subst_char = '^'; + history_comment_char = '#'; + } +} +#endif /* BANG_HISTORY */ + +void +sv_histtimefmt (name) + char *name; +{ + SHELL_VAR *v; + + if (v = find_variable (name)) + { + if (history_comment_char == 0) + history_comment_char = '#'; + } + history_write_timestamps = (v != 0); +} +#endif /* HISTORY */ + +#if defined (HAVE_TZSET) +void +sv_tz (name) + char *name; +{ + if (chkexport (name)) + tzset (); +} +#endif + +/* If the variable exists, then the value of it can be the number + of times we actually ignore the EOF. The default is small, + (smaller than csh, anyway). */ +void +sv_ignoreeof (name) + char *name; +{ + SHELL_VAR *tmp_var; + char *temp; + + eof_encountered = 0; + + tmp_var = find_variable (name); + ignoreeof = tmp_var != 0; + temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; + if (temp) + eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; + set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ +} + +void +sv_optind (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value ("OPTIND"); + if (tt && *tt) + { + s = atoi (tt); + + /* According to POSIX, setting OPTIND=1 resets the internal state + of getopt (). */ + if (s < 0 || s == 1) + s = 0; + } + else + s = 0; + getopts_reset (s); +} + +void +sv_opterr (name) + char *name; +{ + char *tt; + + tt = get_string_value ("OPTERR"); + sh_opterr = (tt && *tt) ? atoi (tt) : 1; +} + +void +sv_strict_posix (name) + char *name; +{ + SET_INT_VAR (name, posixly_correct); + posix_initialize (posixly_correct); +#if defined (READLINE) + if (interactive_shell) + posix_readline_initialize (posixly_correct); +#endif /* READLINE */ + set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ +} + +void +sv_locale (name) + char *name; +{ + char *v; + int r; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + r = set_lang (name, v); + else + r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ + +#if 1 + if (r == 0 && posixly_correct) + last_command_exit_value = 1; +#endif +} + +#if defined (ARRAY_VARS) +void +set_pipestatus_array (ps, nproc) + int *ps; + int nproc; +{ + SHELL_VAR *v; + ARRAY *a; + ARRAY_ELEMENT *ae; + register int i; + char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + + if (a == 0 || array_num_elements (a) == 0) + { + for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + return; + } + + /* Fast case */ + if (array_num_elements (a) == nproc && nproc == 1) + { + ae = element_forw (a->head); + free (element_value (ae)); + ae->value = itos (ps[0]); + } + else if (array_num_elements (a) <= nproc) + { + /* modify in array_num_elements members in place, then add */ + ae = a->head; + for (i = 0; i < array_num_elements (a); i++) + { + ae = element_forw (ae); + free (element_value (ae)); + ae->value = itos (ps[i]); + } + /* add any more */ + for ( ; i < nproc; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } + else + { + /* deleting elements. it's faster to rebuild the array. */ + array_flush (a); + for (i = 0; ps[i] != -1; i++) + { + t = inttostr (ps[i], tbuf, sizeof (tbuf)); + array_insert (a, i, t); + } + } +} + +ARRAY * +save_pipestatus_array () +{ + SHELL_VAR *v; + ARRAY *a, *a2; + + v = find_variable ("PIPESTATUS"); + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return ((ARRAY *)NULL); + + a = array_cell (v); + a2 = array_copy (array_cell (v)); + + return a2; +} + +void +restore_pipestatus_array (a) + ARRAY *a; +{ + SHELL_VAR *v; + ARRAY *a2; + + v = find_variable ("PIPESTATUS"); + /* XXX - should we still assign even if existing value is NULL? */ + if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) + return; + + a2 = array_cell (v); + var_setarray (v, a); + + array_dispose (a2); +} +#endif + +void +set_pipestatus_from_exit (s) + int s; +{ +#if defined (ARRAY_VARS) + static int v[2] = { 0, -1 }; + + v[0] = s; + set_pipestatus_array (v, 1); +#endif +} + +void +sv_xtracefd (name) + char *name; +{ + SHELL_VAR *v; + char *t, *e; + int fd; + FILE *fp; + + v = find_variable (name); + if (v == 0) + { + xtrace_reset (); + return; + } + + t = value_cell (v); + if (t == 0 || *t == 0) + xtrace_reset (); + else + { + fd = (int)strtol (t, &e, 10); + if (e != t && *e == '\0' && sh_validfd (fd)) + { + fp = fdopen (fd, "w"); + if (fp == 0) + internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); + else + xtrace_set (fd, fp); + } + else + internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); + } +} + +#define MIN_COMPAT_LEVEL 31 + +void +sv_shcompat (name) + char *name; +{ + SHELL_VAR *v; + char *val; + int tens, ones, compatval; + + v = find_variable (name); + if (v == 0) + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + val = value_cell (v); + if (val == 0 || *val == '\0') + { + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + /* Handle decimal-like compatibility version specifications: 4.2 */ + if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0) + { + tens = val[0] - '0'; + ones = val[2] - '0'; + compatval = tens*10 + ones; + } + /* Handle integer-like compatibility version specifications: 42 */ + else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0) + { + tens = val[0] - '0'; + ones = val[1] - '0'; + compatval = tens*10 + ones; + } + else + { +compat_error: + internal_error (_("%s: %s: compatibility value out of range"), name, val); + shell_compatibility_level = DEFAULT_COMPAT_LEVEL; + set_compatibility_opts (); + return; + } + + if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) + goto compat_error; + + shell_compatibility_level = compatval; + set_compatibility_opts (); +} + +#if defined (JOB_CONTROL) +void +sv_childmax (name) + char *name; +{ + char *tt; + int s; + + tt = get_string_value (name); + s = (tt && *tt) ? atoi (tt) : 0; + set_maxchild (s); +} +#endif -- 2.47.2