Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / init.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: init.c /main/4 1995/11/17 15:16:52 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
29 *                    AT&T BELL LABORATORIES                    *
30 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
31 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
32 *                                                              *
33 *                Copyright (c) 1995 AT&T Corp.                 *
34 *              Unpublished & Not for Publication               *
35 *                     All Rights Reserved                      *
36 *                                                              *
37 *       The copyright notice above does not evidence any       *
38 *      actual or intended publication of such source code      *
39 *                                                              *
40 *               This software was created by the               *
41 *           Advanced Software Technology Department            *
42 *                    AT&T Bell Laboratories                    *
43 *                                                              *
44 *               For further information contact                *
45 *                    {research,attmail}!dgk                    *
46 *                                                              *
47 ***************************************************************/
48
49 /* : : generated by proto : : */
50
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__      "C"
55 #else
56 #define __MANGLE__
57 #endif
58 #define __STDARG__
59 #define __PROTO__(x)    x
60 #define __OTORP__(x)
61 #define __PARAM__(n,o)  n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
64 #define const
65 #endif
66 #define signed
67 #define void            int
68 #define volatile
69 #define __V_            char
70 #else
71 #define __V_            void
72 #endif
73 #else
74 #define __PROTO__(x)    ()
75 #define __OTORP__(x)    x
76 #define __PARAM__(n,o)  o
77 #define __MANGLE__
78 #define __V_            char
79 #define const
80 #define signed
81 #define void            int
82 #define volatile
83 #endif
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__      ...
86 #else
87 #define __VARARG__
88 #endif
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a)       va_start(p,a)
91 #else
92 #define __VA_START__(p,a)       va_start(p)
93 #endif
94 #endif
95 #include        "defs.h"
96 #include        <stak.h>
97 #include        <ctype.h>
98 #include        "variables.h"
99 #include        "path.h"
100 #include        "fault.h"
101 #include        "name.h"
102 #include        "jobs.h"
103 #include        "io.h"
104 #include        "FEATURE/time"
105 #include        "FEATURE/dynamic"
106 #include        "lexstates.h"
107 #include        "FEATURE/locale"
108 #include        "national.h"
109
110 #if _hdr_wchar && _lib_wctype && _lib_iswctype
111 #   include <wchar.h>
112 #   undef  isalpha
113 #   define isalpha(x)      iswalpha(x)
114 #   undef  isblank
115 #   define isblank(x)      iswblank(x)
116 #   if !_lib_iswblank
117 #if defined(USL)
118 #include <wctype.h>
119 #endif
120
121         static int
122         iswblank __PARAM__((wint_t wc), (wc)) __OTORP__(wint_t wc;){
123                 static int      initialized;
124                 static wctype_t wt;
125
126                 if (!initialized)
127                 {
128                         initialized = 1;
129                         wt = wctype("blank");
130                 }
131                 return(iswctype(wc, wt));
132         }
133 #   endif
134 #else
135 #   undef  _lib_wctype
136 #   ifndef isblank
137 #       define isblank(x)      ((x)==' '||(x)=='\t')
138 #   endif
139 #endif
140
141 #ifdef _hdr_locale
142 #   include     <locale.h>
143 #   ifndef LC_MESSAGES
144 #       define LC_MESSAGES      LC_ALL
145 #   endif /* LC_MESSAGES */
146 #endif /* _hdr_locale */
147
148 #define RANDMASK        0x7fff
149 #ifndef CLK_TCK
150 #   define CLK_TCK      60
151 #endif /* CLK_TCK */
152
153 extern __MANGLE__ char  **environ;
154 #ifdef MTRACE
155     extern __MANGLE__ int Mt_certify;
156 #endif /* MTRACE */
157
158 static void             env_init __PROTO__((void));
159 static void             nv_init __PROTO__((void));
160 static Hashtab_t        *inittree __PROTO__((const struct shtable2*));
161
162 static const char       rsh_pattern[] = "@(rk|kr|r)sh";
163 static int              rand_shift;
164 static Namval_t         *ifsnp;
165
166
167 /*
168  * Invalidate all path name bindings
169  */
170 static void rehash __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
171         nv_onattr(np,NV_NOALIAS);
172 }
173
174 /*
175  * out of memory routine for stak routines
176  */
177 static char *nospace __PARAM__((int unused), (unused)) __OTORP__(int unused;){
178         NOT_USED(unused);
179         error(ERROR_exit(3),e_nospace);
180         return(NIL(char*));
181 }
182
183 #ifdef SHOPT_MULTIBYTE
184 #   include     "edit.h"
185     /* Trap for CSWIDTH variable */
186     static void put_cswidth __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
187         register char *cp;
188         register char *name = nv_name(np);
189         if(ed_setwidth(val?val:"") && !(flags&NV_IMPORT))
190                 error(ERROR_exit(1),e_format,nv_name(np));
191         nv_putv(np, val, flags, fp);
192     }
193 #endif /* SHOPT_MULTIBYTE */
194
195 /* Trap for VISUAL and EDITOR variables */
196 static void put_ed __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
197         register const char *cp, *name=nv_name(np);
198         if(*name=='E' && nv_getval(nv_scoped(VISINOD)))
199                 goto done;
200         sh_offoption(SH_VI|SH_EMACS|SH_GMACS);
201         if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD)))))
202                 goto done;
203         /* turn on vi or emacs option if editor name is either*/
204         cp = path_basename(cp);
205         if(strmatch(cp,"*vi"))
206                 sh_onoption(SH_VI);
207         if(strmatch(cp,"*macs"))
208         {
209                 if(*cp=='g')
210                         sh_onoption(SH_GMACS);
211                 else
212                         sh_onoption(SH_EMACS);
213         }
214 done:
215         nv_putv(np, val, flags, fp);
216 }
217
218 /* Trap for OPTINDEX */
219 static void put_optindex __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
220         sh.st.opterror = sh.st.optchar = 0;
221         nv_putv(np, val, flags, fp);
222 }
223
224 /* Trap for restricted variables PATH, SHELL, ENV */
225 static void put_restricted __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
226         if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
227                 error(ERROR_exit(1),e_restricted,nv_name(np));
228         if(nv_name(np)==nv_name(PATHNOD))                       
229         {
230                 sh.lastpath = 0;
231                 nv_scan(sh.track_tree,rehash,NV_TAGGED,NV_TAGGED);
232         }
233         nv_putv(np, val, flags, fp);
234 }
235
236 #ifdef apollo
237     /* Trap for SYSTYPE variable */
238     static void put_systype __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
239         sh.lastpath = 0;
240         nv_scan(sh.track_tree,rehash,NV_TAGGED,NV_TAGGED);
241         nv_putv(np, val, flags, fp);
242     }
243 #endif
244
245 #ifdef _hdr_locale
246
247 /*
248  * The following struct is based on an alphanumerically sorted list of
249  * all ksh-generated messages which might be displayed, and
250  * must be looked up in a message catalog.  The point of this is to 
251  * translate from the AT&T/UI style of string-based message indexing
252  * to the X/OPEN style of message number lookup.  The following struct
253  * allows us to do a binary search on the strings to find the associated
254  * set number and message ID.  While we could have used the string index 
255  * as the message number, that would cause headaches if/when we
256  * need to add more messages, as all following messages would have to
257  * be renumbered.
258  */
259 typedef struct {
260         char *string;
261         int setNum;
262         int msgNum;
263 } MsgStr, *MsgPtr;
264
265 static MsgStr allmsgs[] = {
266         {" Done", 25, 1},
267         {" Running", 25, 3},
268         {" [-n] [arg...]", 25, 4},
269         {" [arg...]", 25, 5},
270         {" [dir] [list]", 25, 6},
271         {" [job...]", 25, 7},
272         {" [n]", 25, 8},
273         {" [name [pathname] ]", 25, 9},
274         {" [name]", 25, 10},
275         {" [top] [base]", 25, 11},
276         {" expr...", 25, 12},
277         {" format [arg...]", 25, 13},
278         {" is a function", 25, 14},
279         {" is a keyword", 25, 15},
280         {" is a shell builtin", 25, 16},
281         {" is an exported function", 25, 17},
282         {" is an undefined function", 25, 18},
283         {" name [arg...]", 25, 19},
284         {":a:[name] optstring name [args...]", 25, 20},
285         {" seconds", 25, 21},
286         {"${HOME:-.}/.profile", 25, 23},
287         {"%c: invalid character in expression - %s", 25, 24},
288         {"%c: unknown format specifier", 25, 25},
289         {"%d-%d: invalid range", 25, 26},
290         {"%d: invalid binary script version", 25, 27},
291         {"%s is an alias for ", 25, 28},
292         {"%s is an exported alias for ", 25, 29},
293         {"%s missing", 25, 30},
294         {"%s unknown base", 25, 31},
295         {"%s: ':' expected for '?' operator", 25, 32},
296         {"%s: Ambiguous", 25, 33},
297         {"%s: Arguments must be %job or process ids", 25, 34},
298         {"%s: alias not found\n", 25, 35},
299         {"%s: arithmetic syntax error", 25, 36},
300         {"%s: assignment requires lvalue", 25, 37},
301         {"%s: bad file unit number", 25, 38},
302         {"%s: bad format", 25, 39},
303         {"%s: bad number", 25, 40},
304         {"%s: bad option(s)", 25, 41},
305         {"%s: bad substitution", 25, 42},
306         {"%s: bad trap", 25, 43},
307         {"%s: cannot create", 25, 44},
308         {"%s: cannot execute", 25, 45},
309         {"%s: cannot open", 25, 46},
310         {"%s: divide by zero", 25, 47},
311         {"%s: domain exception", 25, 48},
312         {"%s: fails %s", 25, 49},
313         {"%s: file already exists", 25, 50},
314         {"%s: illegal function name", 25, 51},
315         {"%s: invalid alias name", 25, 52},
316         {"%s: invalid discipline function", 25, 53},
317         {"%s: invalid export name", 25, 54},
318         {"%s: invalid function name", 25, 55},
319         {"%s: invalid name", 25, 56},
320         {"%s: invalid regular expression", 25, 57},
321         {"%s: invalid self reference", 25, 58},
322         {"%s: invalid use of :", 25, 59},
323         {"%s: invalid variable name", 25, 60},
324         {"%s: is not an identifier", 25, 61},
325         {"%s: is read only", 25, 62},
326         {"%s: label not implemented", 25, 63},
327         {"%s: limit exceeded", 25, 64},
328         {"%s: more tokens expected", 25, 65},
329         {"%s: no parent", 25, 66},
330         {"%s: no reference name", 25, 67},
331         {"%s: not found", 25, 68},
332         {"%s: not implemented", 25, 69},
333         {"%s: operands have incompatible types", 25, 70},
334         {"%s: overflow exception", 25, 71},
335         {"%s: parameter not set", 25, 72},
336         {"%s: parameter null or not set", 25, 73},
337         {"%s: recursion too deep", 25, 74},
338         {"%s: reference variable cannot be an array", 25, 75},
339         {"%s: requires pathname argument", 25, 76},
340         {"%s: restricted", 25, 77},
341         {"%s: singularity exception", 25, 78},
342         {"%s: subscript out of range", 25, 79},
343         {"%s: unbalanced parenthesis", 25, 80},
344         {"%s: unknown function", 25, 81},
345         {"%s: unknown locale", 25, 82},
346         {"%s: unknown operator", 25, 83},
347         {"%s: unknown signal name", 25, 84},
348         {"%s: would cause loop", 25, 85},
349         {"(coredump)", 25, 86},
350         {"-c requires argument", 25, 87},
351         {"-e - requires single argument", 25, 88},
352         {"/vpix", 25, 89},
353         {"<command unknown>", 25, 90},
354         {"AC:E#?F#?H:[name]L#?R#?Z#?fi#?[base]lnprtux [name=[value]...]", 25, 91},
355         {"AE#?F#?HL#?R#?Z#?fi#?[base]lnprtux [name=[value]...]", 25, 92},
356         {"Abort", 25, 93},
357         {"Ad:[delim]prst#[timeout]u#[filenum] [name...]", 25, 94},
358         {"Alarm call", 25, 95},
359         {"Bad root node specification", 25, 96},
360         {"Bad system call", 25, 97},
361         {"Broken Pipe", 25, 98},
362         {"Bus error", 25, 99},
363         {"Cannot start job control", 25, 100},
364         {"Current option settings", 25, 101},
365         {"DIL signal", 25, 102},
366         {"Death of Child", 25, 103},
367         {"DircabefhkmnpstuvxCR:[file]o:?[option] [arg...]", 25, 104},
368         {"DircabefhkmnpstuvxCo:?[option] [arg...]", 25, 105},
369         {"EMT trap", 25, 106},
370         {"Exceeded CPU time limit", 25, 107},
371         {"Exceeded file size limit", 25, 108},
372         {"Floating exception", 25, 109},
373         {"HSacdfmnstv [limit]", 25, 110},
374         {"Hangup", 25, 111},
375         {"IO signal", 25, 112},
376         {"Illegal instruction", 25, 113},
377         {"Interrupt", 25, 114},
378         {"Killed", 25, 115},
379         {"LP [dir] [change]", 25, 116},
380         {"Memory fault", 25, 117},
381         {"Migrate process", 25, 118},
382         {"No job control", 25, 119},
383         {"Phone interrupt", 25, 120},
384         {"Polling alarm", 25, 121},
385         {"Power fail", 25, 122},
386         {"Profiling time alarm", 25, 123},
387         {"Quit", 25, 124},
388         {"Resources lost", 25, 125},
389         {"Reverting to old tty driver...", 25, 126},
390         {"S [mask]", 25, 127},
391         {"SIGAPOLLO", 25, 128},
392         {"Security label changed", 25, 129},
393         {"Socket interrupt", 25, 130},
394         {"Sound completed", 25, 131},
395         {"Stopped (signal)", 25, 132},
396         {"Stopped (tty input)", 25, 133},
397         {"Stopped process continued", 25, 134},
398         {"Stopped", 25, 135},
399         {"Stopped(tty output)", 25, 136},
400         {"Switching to new tty driver...", 25, 137},
401         {"System crash soon", 25, 138},
402         {"Terminated", 25, 139},
403         {"Trace/BPT trap", 25, 140},
404         {"Unrecognized version", 25, 141},
405         {"Use 'exit' to terminate this shell", 25, 142},
406         {"User signal 1", 25, 143},
407         {"User signal 2", 25, 144},
408         {"Version not defined", 25, 145},
409         {"Virtual time alarm", 25, 146},
410         {"Window size change", 25, 147},
411         {"You have running jobs", 25, 148},
412         {"You have stopped jobs", 25, 149},
413         {"[_[:alpha:]]*([_[:alnum:]])", 25, 150},
414         {"\n@(#)Version 12/28/93\0\n", 25, 151},
415         {"\n@(#)Version M-12/28/93\0\n", 25, 152},
416         {"\nreal", 25, 153},
417         {"\r\n\007shell will timeout in 60 seconds due to inactivity", 25, 154},
418         {"a name...", 25, 155},
419         {"a:c [command [args...] ]", 25, 156},
420         {"afpv name...", 25, 157},
421         {"alarm %s %.3f\n", 25, 158},
422         {"alarm -r %s +%.3g\n", 25, 159},
423         {"argument expected", 25, 160},
424         {"bad directory", 25, 161},
425         {"bad file unit number", 25, 162},
426         {"bad substitution", 25, 163},
427         {"cannot access parent directories", 25, 164},
428         {"cannot create pipe", 25, 165},
429         {"cannot create tempory file", 25, 166},
430         {"cannot fork", 25, 167},
431         {"cannot get %s", 25, 168},
432         {"cannot set %s", 25, 169},
433         {"cannot set alarm", 25, 170},
434         {"condition(s) required", 25, 171},
435         {"dsf:[library] [name...]", 25, 172},
436         {"e:[editor]lnrsN# [first] [last]", 25, 173},
437         {"end of file", 25, 174},
438         {"f:[format]enprsu:[filenum] [arg...]", 25, 175},
439         {"fnv name...", 25, 176},
440         {"hist -e \"${VISUAL:-${EDITOR:-vi}}\" ", 25, 177},
441         {"history file cannot open", 25, 178},
442         {"incorrect syntax", 25, 179},
443         {"invalid argument of type %c", 25, 180},
444         {"is a shell builtin version of", 25, 181},
445         {"is a tracked alias for", 25, 182},
446         {"kill", 25, 183},
447         {"line %d: $ not preceeded by \\", 25, 184},
448         {"line %d: %c within ${} should be quoted", 25, 185},
449         {"line %d: %s unknown label", 25, 186},
450         {"line %d: %s within [[...]] obsolete, use ((...))", 25, 187},
451         {"line %d: '=' obsolete, use '=='", 25, 188},
452         {"line %d: -a obsolete, use -e", 25, 189},
453         {"line %d: \\ in front of %c reserved for future use", 25, 190},
454         {"line %d: `...` obsolete, use $(...)", 25, 191},
455         {"line %d: escape %c to avoid ambiguities", 25, 192},
456         {"line %d: label %s ignored", 25, 193},
457         {"line %d: quote %c to avoid ambiguities", 25, 194},
458         {"line %d: set %s obsolete", 25, 195},
459         {"line %d: spaces required for nested subshell", 25, 196},
460         {"line %d: use braces to avoid ambiguities with $id[...]", 25, 197},
461         {"line %d: use space or tab to separate operators %c and %c", 25, 198},
462         {"ln#[signum]s:[signame] sig...", 25, 199},
463         {"login setuid/setgid shells prohibited", 25, 200},
464         {"mapping", 25, 201},
465         {"newline", 25, 202},
466         {"nlp [job...]", 25, 203},
467         {"no history file", 25, 204},
468         {"no query process", 25, 205},
469         {"no such job", 25, 206},
470         {"no such process", 25, 207},
471         {"not supported", 25, 208},
472         {"off", 25, 209},
473         {"on", 25, 210},
474         {"open file limit exceeded", 25, 211},
475         {"out of memory", 25, 212},
476         {"p [action condition...]", 25, 213},
477         {"p [name[=value]...]", 25, 214},
478         {"parameter not set", 25, 215},
479         {"permission denied", 25, 216},
480         {"process already exists", 25, 217},
481         {"ptx [name=[value]...]", 25, 218},
482         {"pvV name [arg]...", 25, 219},
483         {"r [varname seconds]", 25, 220},
484         {"syntax error at line %d: `%s' %s", 25, 221},
485         {"syntax error at line %d: duplicate label %s", 25, 222},
486         {"syntax error: `%s' %s", 25, 223},
487         {"sys", 25, 224},
488         {"timed out waiting for input", 25, 225},
489         {"unexpected", 25, 226},
490         {"universe not accessible", 25, 227},
491         {"unlimited", 25, 228},
492         {"unmatched", 25, 229},
493         {"user", 25, 230},
494         {"versions", 25, 231},
495         {"write to %d failed", 25, 232},
496         {"you have mail in $_", 25, 233},
497         {"zero byte", 25, 234},
498 };
499 #ifdef __ultrix
500 #define _CLIENT_CAT_NAME "dtksh.cat"
501 #else  /* __ultrix */
502 #define _CLIENT_CAT_NAME "dtksh"
503 #endif /* __ultrix */
504
505 /*
506  * Without this proto, standard C says that _DtGetMessage() returns
507  * an int, even though it really returns a pointer.  The compiler is
508  * then free to use the high 32-bits of the return register for
509  * something else (like scratch), and that can garble the pointer.
510  */
511 char *_DtGetMessage __PROTO__((char *filename, int set, int n, char *s));
512 #define GETMESSAGE(set, number, string)\
513         (_DtGetMessage(_CLIENT_CAT_NAME, set, number, string))
514
515 #include <nl_types.h>
516
517 static int localeChanged = 1;
518
519     void LocaleChanged __PARAM__((Namval_t *np, const char *val, int flags, Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t *np; const char *val; int flags; Namfun_t *fp;)
520 {
521    localeChanged = 1;
522    nv_putv(np, val, flags, fp);
523    setlocale(LC_ALL, "");
524 }
525
526
527 /****************************************************************************
528  *
529  * The following two functions are ugly, but necessary.  Ksh reserves file
530  * descriptors 0 - 9 for use by shell scripts, and has intimate knowledge
531  * of how and when they were opened.  Unfortunately, certain dtksh functions
532  * (XtInitialize, catopen, ttdt_open, _DtActionInvoke, others) open file
533  * descriptors which are not known to ksh.  We can't let these file
534  * descriptors fall in the 0 - 9 range, because we can't afford to have
535  * the shell script overriding our file descriptors.  Therefore, any of
536  * our commands which open files must first lock our file descriptors 0 - 9,
537  * thus forcing the command to get a file descriptor out of the shell's
538  * range.  After the command has opened its file descriptor, it then needs
539  * to unlock file descriptors 0 - 9, so that the shell script will have
540  * access to them again.
541  *
542  **************************************************************************/
543
544
545 /*
546  * Return a list of the file descriptors we had to open, to lock out file
547  * descriptors 0 - 9; this list should be freed (and the file descriptors
548  * closed) by calling UnlockkshFileDescriptors().
549  */
550
551     int *LockKshFileDescriptors __PARAM__((void),())
552 {
553    int * fdList;
554    int i;
555    int fd, newfd;
556
557    fdList = (int *)malloc(sizeof(int) * 10);
558    for (i = 0; i < 10; i++)
559       fdList[i] = -1;
560
561    if ((fd = open("/dev/null", O_RDONLY)) >= 0)
562    {
563       if (fd < 10)
564       {
565          fdList[0] = fd;
566          for (i = 1; i < 10; i++)
567          {
568             if ((newfd = dup(fd)) < 10)
569                fdList[i] = newfd;
570             else
571             {
572                close(newfd);
573                break;
574             }
575          }
576       }
577       else
578          close(fd);
579    }
580
581    return(fdList);
582 }
583
584     void UnlockKshFileDescriptors __PARAM__((int *fdList), (fdList)) __OTORP__(int *fdList;)
585 {
586    int i;
587
588    for (i = 0; i < 10; i++)
589    {
590       if (fdList[i] != (-1))
591          close(fdList[i]);
592    }
593
594    free((char *)fdList);
595 }
596
597 /*
598  * This function overrides the traditional libDtSvc version of this function.
599  * Since ksh dynamically changes to match the user's locale, we potentially
600  * need to change our message catalog in the middle of running.
601  */
602 char *savedNlsPath;
603
604     char *_DtGetMessage __PARAM__((char *filename, int set, int n, char *s), (filename, set, n, s)) __OTORP__(char *filename; int set; int n; char *s;)
605 {
606         nl_catd catopen();
607         char *catgets();
608         int catclose();
609
610         static nl_catd nlmsg_fd = (nl_catd)-1;
611         static char *lang = NULL;
612         char *msg;
613         char * newLang;
614         int * lockedFds;
615         int swappedNlsPath = 0;
616         char *pEqual;
617         static char pathBuf[1024] = {(char)'N', (char)'L', (char)'S', (char)'P',
618                                                                 (char)'A', (char)'T', (char)'H', (char)'='};
619
620         if ( localeChanged ) 
621         {
622                 char *oldPath;
623                 localeChanged = 0;
624
625                 newLang = (char *) getenv ("LANG");
626                 if (lang)
627                    free(lang);
628                 if (newLang)
629                    lang = strdup(newLang);
630                 else
631                    lang = NULL;
632
633                 if (nlmsg_fd != (nl_catd)-1)
634                    catclose(nlmsg_fd);
635                 if(strcmp((oldPath = getenv("NLSPATH")), savedNlsPath) != 0)
636                 {
637                         swappedNlsPath = 1;
638                         pEqual = strchr(pathBuf, '=');
639                         strcpy(pEqual + 1, savedNlsPath);
640                         /*
641                          * Only call putenv if pathBuf isn't already holding NLSPATH
642                          * in the environment.
643                          */
644                         if(oldPath != (pEqual + 1))
645                             putenv(pathBuf);
646                 }
647                 lockedFds = LockKshFileDescriptors();
648                 nlmsg_fd = catopen(filename, 0);
649                 UnlockKshFileDescriptors(lockedFds);
650                 if(swappedNlsPath != 0)
651                 {
652                         swappedNlsPath = 0;
653                         pEqual = strchr(pathBuf, '=');
654                         strcpy(pEqual + 1, oldPath);
655                         if(oldPath != (pEqual + 1))
656                             putenv(pathBuf);
657                 }
658         }
659         msg=catgets(nlmsg_fd,set,n,s);
660         return (msg);
661 }
662
663     /*
664      * This function needs to be modified to handle international
665      * error message translations
666      */
667     static char *msg_translate __PARAM__((const char *message,int type), (message, type)) __OTORP__(const char *message;int type;)
668 {
669         int startIndex = 0, endIndex = sizeof(allmsgs)/sizeof(MsgStr) - 1, 
670             midIndex, res, weFoundIt = 0;
671         
672         if(type != 1) /* if it's not a shell message, don't translate */
673             return((char*)message);
674
675         while(startIndex != endIndex)
676         {
677                 midIndex = (startIndex + endIndex) / 2;
678                 if(midIndex == startIndex)
679                 {
680                         if((res = strcmp(allmsgs[startIndex].string, message)) == 0)
681                         {
682                                 weFoundIt = 1;
683                                 midIndex = startIndex;
684                                 break;
685                         }
686                         else if(res < 0)
687                         {
688                                 if((res = strcmp(allmsgs[endIndex].string, message)) == 0)
689                                 {
690                                         weFoundIt = 1;
691                                         midIndex = endIndex;
692                                         break;
693                                 }
694                         }
695                         /* we didn't find a match in the table */
696                         weFoundIt = 0;
697                         break;
698                 }
699                 else
700                 {
701                         if((res = strcmp(allmsgs[midIndex].string, message)) == 0)
702                         {
703                                 weFoundIt = 1;
704                                 break; /* we found it */
705                         }
706                         else if(res < 0)
707                                 startIndex = midIndex;
708                         else
709                                 endIndex = midIndex;
710                 }
711         }
712         if(weFoundIt)
713                 return GETMESSAGE(allmsgs[midIndex].setNum, allmsgs[midIndex].msgNum, (char *)message);
714
715         return((char*)message);
716     }
717
718
719 #   ifdef SHOPT_MULTIBYTE
720         void charsize_init __PARAM__((void), ()){
721                 static char fc[3] = { 0301,  ESS2, ESS3};
722                 char buff[8];
723                 register int i,n;
724                 wchar_t wc;
725                 memset(buff,0301,MB_CUR_MAX);
726                 for(i=0; i<=2; i++)
727                 {
728                         buff[0] = fc[i];
729                         if((n=mbtowc(&wc,buff,MB_CUR_MAX))>0)
730                         {
731                                 if((int_charsize[i+1] = n-(i>0))>0)
732                                         int_charsize[i+5] = wcwidth(wc);
733                                 else
734                                         int_charsize[i+5] = 0;
735                         }
736                 }
737         }
738 #   endif /* SHOPT_MULTIBYTE */
739
740     /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */
741     static void put_lang __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
742         int type;
743         char *lc_all = nv_getval(LCALLNOD);
744         if(nv_name(np)==nv_name(LCTYPENOD))
745                 type = LC_CTYPE;
746         else if(nv_name(np)==nv_name(LCMSGNOD))
747                 type = LC_MESSAGES;
748         else if(nv_name(np)==nv_name(LCCOLLNOD))
749                 type = LC_COLLATE;
750         else if(nv_name(np)==nv_name(LCNUMNOD))
751                 type = LC_NUMERIC;
752         else if(nv_name(np)==nv_name(LANGNOD) && !lc_all)
753                 type= -1;
754         else
755                 type = LC_ALL;
756         if(type>=0 && type!=LC_ALL && !lc_all)
757                 type= -1;
758         if(type>=0)
759         {
760                 if(!setlocale(type,val?val:""))
761                 {
762                         error(0,e_badlocale,val);
763                         return;
764                 }
765         }
766         if(type==LC_ALL || type==LC_CTYPE)
767         {
768                 if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
769                         free((__V_*)sh_lexstates[ST_BEGIN]);
770                 if(ast.locale.set&LC_SET_CTYPE)
771                 {
772                         register int c;
773                         char *state[4];
774                         sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
775                         memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
776                         sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
777                         memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
778                         sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
779                         memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
780                         sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
781                         memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
782                         for(c=0; c<(1<<CHAR_BIT); c++)
783                         {
784                                 if(isblank(c))
785                                 {
786                                         state[0][c]=0;
787                                         state[1][c]=S_BREAK;
788                                         state[2][c]=S_BREAK;
789                                         continue;
790                                 }
791                                 if(!isalpha(c))
792                                         continue;
793                                 if(state[0][c]==S_REG)
794                                         state[0][c]=S_NAME;
795                                 if(state[1][c]==S_REG)
796                                         state[1][c]=0;
797                                 if(state[2][c]==S_ERR)
798                                         state[2][c]=S_ALP;
799                                 if(state[3][c]==S_ERR)
800                                         state[3][c]=0;
801                         }
802                 }
803                 else
804                 {
805                         sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
806                         sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
807                         sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
808                         sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
809                 }
810 #ifdef SHOPT_MULTIBYTE
811                 charsize_init();
812 #endif /* SHOPT_MULTIBYTE */
813         }
814         if(type==LC_ALL || type==LC_MESSAGES)
815                 error_info.translate = msg_translate;
816         nv_putv(np, val, flags, fp);
817     }
818 #endif /* _hdr_locale */
819
820 /* Trap for IFS assignment and invalidates state table */
821 static void put_ifs __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
822         ifsnp = 0;
823         nv_putv(np, val, flags, fp);
824 }
825
826 /*
827  * This is the lookup function for IFS
828  * It keeps the sh.ifstable up to date
829  */
830 static char* get_ifs __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
831         register char *cp, *value;
832         register int c,n;
833         value = nv_getv(np,fp);
834         if(np!=ifsnp)
835         {
836                 ifsnp = np;
837                 memset(sh.ifstable,0,(1<<CHAR_BIT));
838                 if(cp=value)
839                 {
840 #ifdef SHOPT_MULTIBYTE
841                         while(n=mbtowc(0,cp,MB_CUR_MAX),c= *(unsigned char*)cp)
842 #else
843                         while(c= *(unsigned char*)cp++)
844 #endif /* SHOPT_MULTIBYTE */
845                         {
846 #ifdef SHOPT_MULTIBYTE
847                                 cp+=n;
848                                 if(n>1)
849                                 {
850                                         sh.ifstable[c] = S_MBYTE;
851                                         continue;
852                                 }
853 #endif /* SHOPT_MULTIBYTE */
854                                 n = S_DELIM;
855                                 if(c== *cp)
856                                         cp++;
857                                 else if(isspace(c))
858                                         n = S_SPACE;
859                                 sh.ifstable[c] = n;
860                         }
861                 }
862                 else
863                 {
864                         sh.ifstable[' '] = sh.ifstable['\t'] = S_SPACE;
865                         sh.ifstable['\n'] = S_NL;
866                 }
867         }
868         return(value);
869 }
870
871 /*
872  * these functions are used to get and set the SECONDS variable
873  */
874 #ifdef _lib_gettimeofday
875 #   define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
876 #   define tms  timeval
877 #else
878 #   define dtime(tp)    (((double)times(tp))/sh.lim.clk_tck)
879 #   define gettimeofday(a,b)
880 #endif
881
882 static void put_seconds __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
883         static double sec_offset;
884         double d;
885         struct tms tp;
886         NOT_USED(fp);
887         if(!val)
888         {
889                 nv_stack(np, NIL(Namfun_t*));
890                 nv_unset(np);
891                 return;
892         }
893         if(flags&NV_INTEGER)
894                 d = *(double*)val;
895         else
896                 d = sh_arith(val);
897         gettimeofday(&tp,NIL(void *));
898         sec_offset = dtime(&tp)-d;
899         if(!np->nvalue.dp)
900         {
901                 nv_setsize(np,3);
902                 np->nvalue.dp = &sec_offset;
903         }
904 }
905
906 static char* get_seconds __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
907         struct tms tp;
908         double d;
909         NOT_USED(fp);
910         gettimeofday(&tp,NIL(void *));
911         d = dtime(&tp)- *np->nvalue.dp;
912         return(sh_ftos(d,nv_size(np)));
913 }
914
915 static double nget_seconds __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
916         struct tms tp;
917         NOT_USED(fp);
918         gettimeofday(&tp,NIL(void *));
919         return(dtime(&tp)- *np->nvalue.dp);
920 }
921
922 /*
923  * These three functions are used to get and set the RANDOM variable
924  */
925 static void put_rand __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
926         static long rand_last;
927         register long n;
928         NOT_USED(fp);
929         if(!val)
930         {
931                 nv_stack(np, NIL(Namfun_t*));
932                 nv_unset(np);
933                 return;
934         }
935         if(flags&NV_INTEGER)
936                 n = *(double*)val;
937         else
938                 n = sh_arith(val);
939         srand((int)(n&RANDMASK));
940         rand_last = -1;
941         if(!np->nvalue.lp)
942                 np->nvalue.lp = &rand_last;
943 }
944
945 /*
946  * get random number in range of 0 - 2**15
947  * never pick same number twice in a row
948  */
949 static double nget_rand __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
950         register long cur, last= *np->nvalue.lp;
951         NOT_USED(fp);
952         do
953                 cur = (rand()>>rand_shift)&RANDMASK;
954         while(cur==last);
955         *np->nvalue.lp = cur;
956         return((double)cur);
957 }
958
959 static char* get_rand __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
960         register long n = nget_rand(np,fp);
961         return(fmtbase(n, 10, 0));
962 }
963
964 /*
965  * These three routines are for LINENO
966  */
967 static double nget_lineno __PARAM__((Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(Namval_t* np; Namfun_t *fp;){
968         double d=1;
969         if(error_info.line >0)
970                 d = error_info.line;
971         else if(error_info.context && error_info.context->line>0)
972                 d = error_info.context->line;
973         NOT_USED(np);
974         NOT_USED(fp);
975         return(d);
976 }
977
978 static void put_lineno __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
979         register long n;
980         NOT_USED(fp);
981         if(!val)
982         {
983                 nv_stack(np, NIL(Namfun_t*));
984                 nv_unset(np);
985                 return;
986         }
987         if(flags&NV_INTEGER)
988                 n = *(double*)val;
989         else
990                 n = sh_arith(val);
991         sh.st.firstline += nget_lineno(np,fp)+1-n;
992 }
993
994 static char* get_lineno __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
995         register long n = nget_lineno(np,fp);
996         return(fmtbase(n, 10, 0));
997 }
998
999 static char* get_lastarg __PARAM__((Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(Namval_t* np; Namfun_t *fp;){
1000         NOT_USED(np);
1001         NOT_USED(fp);
1002         return(sh.lastarg);
1003 }
1004
1005 static void put_lastarg __PARAM__((Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(Namval_t* np;const char *val;int flags;Namfun_t *fp;){
1006         NOT_USED(fp);
1007         if(flags&NV_INTEGER)
1008                 val = sh_etos(*((double*)val),12);
1009         if(sh.lastarg && !nv_isattr(np,NV_NOFREE))
1010                 free((__V_*)sh.lastarg);
1011         else
1012                 nv_offattr(np,NV_NOFREE);
1013         if(val)
1014                 sh.lastarg = strdup(val);
1015         else
1016                 sh.lastarg = 0;
1017 }
1018
1019 #ifdef SHOPT_FS_3D
1020     /*
1021      * set or unset the mappings given a colon separated list of directories
1022      */
1023     static void vpath_set __PARAM__((char *str, int mode), (str, mode)) __OTORP__(char *str; int mode;){
1024         register char *lastp, *oldp=str, *newp=strchr(oldp,':');
1025         if(!sh.lim.fs3d)
1026                 return;
1027         while(newp)
1028         {
1029                 *newp++ = 0;
1030                 if(lastp=strchr(newp,':'))
1031                         *lastp = 0;
1032                 mount((mode?newp:""),oldp,FS3D_VIEW,0);
1033                 newp[-1] = ':';
1034                 oldp = newp;
1035                 newp=lastp;
1036         }
1037     }
1038
1039     /* catch vpath assignments */
1040     static void put_vpath __PARAM__((register Namval_t* np,const char *val,int flags,Namfun_t *fp), (np, val, flags, fp)) __OTORP__(register Namval_t* np;const char *val;int flags;Namfun_t *fp;){
1041         register char *cp;
1042         if(cp = nv_getval(np))
1043                 vpath_set(cp,0);
1044         if(val)
1045                 vpath_set((char*)val,1);
1046         nv_putv(np,val,flags,fp);
1047     }
1048     static const Namdisc_t VPATH_disc   = { 0, put_vpath  };
1049     static Namfun_t VPATH_init  = { &VPATH_disc  };
1050 #endif /* SHOPT_FS_3D */
1051
1052 static const Namdisc_t IFS_disc         = {  0, put_ifs, get_ifs };
1053 static const Namdisc_t RESTRICTED_disc  = {  0, put_restricted };
1054 static const Namdisc_t EDITOR_disc      = {  0, put_ed };
1055 static const Namdisc_t OPTINDEX_disc    = {  0, put_optindex };
1056 static const Namdisc_t SECONDS_disc     = {  0, put_seconds, get_seconds, nget_seconds };
1057 static const Namdisc_t RAND_disc        = {  0, put_rand, get_rand, nget_rand };
1058 static const Namdisc_t LINENO_disc      = {  0, put_lineno, get_lineno, nget_lineno };
1059 static const Namdisc_t L_ARG_disc       = {  0, put_lastarg, get_lastarg };
1060 static Namfun_t IFS_init        = {  &IFS_disc};
1061 static Namfun_t PATH_init       = {  &RESTRICTED_disc};
1062 static Namfun_t SHELL_init      = {  &RESTRICTED_disc};
1063 static Namfun_t ENV_init        = {  &RESTRICTED_disc};
1064 static Namfun_t VISUAL_init     = {  &EDITOR_disc};
1065 static Namfun_t EDITOR_init     = {  &EDITOR_disc};
1066 static Namfun_t OPTINDEX_init   = {  &OPTINDEX_disc};
1067 static Namfun_t SECONDS_init    = {  &SECONDS_disc};
1068 static Namfun_t RAND_init       = {  &RAND_disc};
1069 static Namfun_t LINENO_init     = {  &LINENO_disc};
1070 static Namfun_t L_ARG_init      = {  &L_ARG_disc};
1071 #ifdef _hdr_locale
1072     static const Namdisc_t LC_disc      = {  0, put_lang };
1073     static Namfun_t LC_TYPE_init        = {  &LC_disc};
1074     static Namfun_t LC_NUM_init         = {  &LC_disc};
1075     static Namfun_t LC_COLL_init        = {  &LC_disc};
1076     static Namfun_t LC_MSG_init         = {  &LC_disc};
1077     static Namfun_t LC_ALL_init         = {  &LC_disc};
1078     static Namfun_t LANG_init           = {  &LC_disc};
1079 #endif /* _hdr_locale */
1080 #ifdef apollo
1081     static const Namdisc_t SYSTYPE_disc = {  0, put_systype };
1082     static Namfun_t SYSTYPE_init        = {  &SYSTYPEdisc};
1083 #endif /* apollo */
1084 #ifdef SHOPT_MULTIBYTE
1085     static const Namdisc_t CSWIDTH_disc = {  0, put_cswidth };
1086     static Namfun_t CSWIDTH_init        = {  &CSWIDTH_disc};
1087 #endif /* SHOPT_MULTIBYTE */
1088
1089 /*
1090  * This function will get called whenever a configuration parameter changes
1091  */
1092 static int newconf __PARAM__((const char *name, const char *path, const char *value), (name, path, value)) __OTORP__(const char *name; const char *path; const char *value;){
1093         register char *arg;
1094         if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
1095         {
1096                 sh.universe = 0;
1097                 /* set directory in new universe */
1098                 if(*(arg = path_pwd(0))=='/')
1099                         chdir(arg);
1100                 /* clear out old tracked alias */
1101                 stakseek(0);
1102                 stakputs(nv_getval(PATHNOD));
1103                 stakputc(0);
1104                 nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
1105         }
1106         return(1);
1107 }
1108
1109 /*
1110  * initialize the shell
1111  */
1112 int sh_init __PARAM__((register int argc,register char *argv[]), (argc, argv)) __OTORP__(register int argc;register char *argv[];){
1113         register char *name;
1114         register int n,prof;
1115 #ifdef MTRACE
1116         Mt_certify = 1;
1117 #endif /* MTRACE */
1118         memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
1119         sh_onstate(SH_INIT);
1120         error_info.exit = sh_exit;
1121         error_info.id = path_basename(argv[0]);
1122         sh.cpipe[0] = -1;
1123         sh.coutpipe = -1;
1124         sh.userid=getuid();
1125         sh.euserid=geteuid();
1126         sh.groupid=getgid();
1127         sh.egroupid=getegid();
1128         for(n=0;n < 10; n++)
1129         {
1130                 /* don't use lower bits when rand() generates large numbers */
1131                 if(rand() > RANDMASK)
1132                 {
1133                         rand_shift = 3;
1134                         break;
1135                 }
1136         }
1137         sh.lim.clk_tck = sysconf(_SC_CLK_TCK);
1138         sh.lim.open_max = sysconf(_SC_OPEN_MAX);
1139         sh.lim.child_max = sysconf(_SC_CHILD_MAX);
1140         sh.lim.ngroups_max = sysconf(_SC_NGROUPS_MAX);
1141         sh.lim.posix_version = sysconf(_SC_VERSION);
1142         sh.lim.posix_jobcontrol = sysconf(_SC_JOB_CONTROL);
1143         if(sh.lim.child_max <=0)
1144                 sh.lim.child_max = CHILD_MAX;
1145         if(sh.lim.open_max <0)
1146                 sh.lim.open_max = OPEN_MAX;
1147         if(sh.lim.clk_tck <=0)
1148                 sh.lim.clk_tck = CLK_TCK;
1149 #ifdef SHOPT_FS_3D
1150         if(mount(".", NIL(char*),FS3D_GET|FS3D_VERSION,0) >= 0)
1151                 sh.lim.fs3d = 1;
1152 #endif /* SHOPT_FS_3D */
1153         sh_ioinit();
1154         /* initialize signal handling */
1155         sh_siginit();
1156         stakinstall(NIL(Stak_t*),nospace);
1157         /* set up memory for name-value pairs */
1158         nv_init();
1159         /* read the environment */
1160 #ifdef SHOPT_MULTIBYTE
1161         charsize_init();
1162 #endif /* SHOPT_MULTIBYTE */
1163         env_init();
1164         nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
1165 #ifdef SHOPT_FS_3D
1166         nv_stack(VPATHNOD, &VPATH_init);
1167 #endif /* SHOPT_FS_3D */
1168         astconfdisc(newconf);
1169 #ifdef SHOPT_TIMEOUT
1170         sh.tmout = SHOPT_TIMEOUT;
1171 #endif /* SHOPT_TIMEOUT */
1172         /* initialize jobs table */
1173         job_clear();
1174         if(argc>0)
1175         {
1176                 name = path_basename(*argv);
1177                 if(*name=='-')
1178                 {
1179                         name++;
1180                         sh.login_sh = 2;
1181                 }
1182                 /* check for restricted shell */
1183                 if(argc>0 && strmatch(name,rsh_pattern))
1184                         sh_onoption(SH_RESTRICTED);
1185                 /* look for options */
1186                 /* sh.st.dolc is $#     */
1187                 if((sh.st.dolc = sh_argopts(-argc,argv)) < 0)
1188                 {
1189                         sh.exitval = 2;
1190                         sh_done(0);
1191                 }
1192                 sh.st.dolv=argv+(argc-1)-sh.st.dolc;
1193                 sh.st.dolv[0] = argv[0];
1194                 if(sh.st.dolc < 1)
1195                         sh_onoption(SH_SFLAG);
1196                 if(!sh_isoption(SH_SFLAG))
1197                 {
1198                         sh.st.dolc--;
1199                         sh.st.dolv++;
1200                 }
1201         }
1202         /* set[ug]id scripts require the -p flag */
1203         prof = !sh_isoption(SH_PRIVILEGED);
1204         if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid)
1205         {
1206 #ifdef SHOPT_P_SUID
1207                 /* require sh -p to run setuid and/or setgid */
1208                 if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID)
1209                 {
1210                         setuid(sh.euserid=sh.userid);
1211                         seTgid(sh.egroupid=sh.groupid);
1212                 }
1213                 else
1214 #else
1215                 {
1216                         sh_onoption(SH_PRIVILEGED);
1217                         prof = 0;
1218                 }
1219 #endif /* SHOPT_P_SUID */
1220 #ifdef SHELLMAGIC
1221                 /* careful of #! setuid scripts with name beginning with - */
1222                 if(sh.login_sh && strcmp(argv[0],argv[1])==0)
1223                         error(ERROR_exit(1),e_prohibited);
1224 #endif /*SHELLMAGIC*/
1225         }
1226         else
1227                 sh_offoption(SH_PRIVILEGED);
1228         sh.shname = strdup(sh.st.dolv[0]); /* shname for $0 in profiles */
1229         /*
1230          * return here for shell script execution
1231          * but not for parenthesis subshells
1232          */
1233         error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */
1234         sh_offstate(SH_INIT);
1235         return(prof);
1236 }
1237
1238 /*
1239  * reinitialize before executing a script
1240  */
1241 void sh_reinit __PARAM__((char *argv[]), (argv)) __OTORP__(char *argv[];){
1242         /* remove locals */
1243         nv_scan(sh.var_tree,sh_envnolocal,NV_EXPORT,0);
1244         hashfree(sh.fun_tree);
1245         sh.fun_tree = hashalloc(sh.bltin_tree,HASH_set,HASH_SCOPE|HASH_ALLOCATE,0);
1246         hashfree(sh.alias_tree);
1247         sh.alias_tree = inittree(shtab_aliases);
1248         /* set up new args */
1249         sh.arglist = sh_argcreate(argv);
1250 }
1251
1252 /*
1253  * set when creating a local variable of this name
1254  */
1255 Namfun_t *nv_cover __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1256         register Namfun_t *nfp=0;
1257         if(np==IFSNOD)
1258                 nfp = &IFS_init;
1259         else if(np==PATHNOD)
1260                 nfp = &PATH_init;
1261         else if(np==SHELLNOD)
1262                 nfp = &SHELL_init;
1263         return(nfp);
1264 }
1265
1266 /*
1267  * Initialize the shell name and alias table
1268  */
1269 static void nv_init __PARAM__((void), ()){
1270         double d=0;
1271         sh.var_base = sh.var_tree = inittree(shtab_variables);
1272         nv_stack(IFSNOD, &IFS_init);
1273         nv_stack(PATHNOD, &PATH_init);
1274         nv_stack(SHELLNOD, &SHELL_init);
1275         nv_stack(ENVNOD, &ENV_init);
1276         nv_stack(VISINOD, &VISUAL_init);
1277         nv_stack(EDITNOD, &EDITOR_init);
1278         nv_stack(OPTINDNOD, &OPTINDEX_init);
1279         nv_stack(SECONDS, &SECONDS_init);
1280         nv_stack(L_ARGNOD, &L_ARG_init);
1281         nv_putval(SECONDS, (char*)&d, NV_INTEGER);
1282         nv_stack(RANDNOD, &RAND_init);
1283         d = (sh.pid&RANDMASK);
1284         nv_putval(RANDNOD, (char*)&d, NV_INTEGER);
1285         nv_stack(LINENO, &LINENO_init);
1286 #ifdef _hdr_locale
1287         nv_stack(LCTYPENOD, &LC_TYPE_init);
1288         nv_stack(LCALLNOD, &LC_ALL_init);
1289         nv_stack(LCMSGNOD, &LC_MSG_init);
1290         nv_stack(LCCOLLNOD, &LC_COLL_init);
1291         nv_stack(LCNUMNOD, &LC_NUM_init);
1292         nv_stack(LANGNOD, &LANG_init);
1293 #endif /* _hdr_locale */
1294 #ifdef apollo
1295         nv_stack(SYSTYPENOD, &SYSTYPE_init);
1296 #endif /* apollo */
1297 #ifdef SHOPT_MULTIBYTE
1298         nv_stack(CSWIDTHNOD, &CSWIDTH_init);
1299 #endif /* SHOPT_MULTIBYTE */
1300         (PPIDNOD)->nvalue.lp = (&sh.ppid);
1301         (TMOUTNOD)->nvalue.lp = (&sh.tmout);
1302         (MCHKNOD)->nvalue.lp = (long*)(&sh_mailchk);
1303         (OPTINDNOD)->nvalue.lp = (&sh.st.optindex);
1304         /* set up the seconds clock */
1305         sh.alias_tree = inittree(shtab_aliases);
1306         sh.track_tree = hashalloc(sh.var_tree,HASH_set,HASH_ALLOCATE,0);
1307         sh.bltin_tree = inittree((const struct shtable2*)shtab_builtins);
1308         sh.fun_tree = hashalloc(sh.bltin_tree,HASH_set,HASH_SCOPE|HASH_ALLOCATE,0);
1309 }
1310
1311 /*
1312  * initialize name-value pairs
1313  */
1314
1315 static Hashtab_t *inittree __PARAM__((const struct shtable2 *name_vals), (name_vals)) __OTORP__(const struct shtable2 *name_vals;){
1316         register Namval_t *np;
1317         register const struct shtable2 *tp;
1318         register unsigned n = 0;
1319         register Hashtab_t *treep;
1320         for(tp=name_vals;*tp->sh_name;tp++)
1321                 n++;
1322         np = (Namval_t*)calloc(n,sizeof(Namval_t));
1323         if(!sh.bltin_nodes)
1324                 sh.bltin_nodes = np;
1325         else if(name_vals==(const struct shtable2*)shtab_builtins)
1326                 sh.bltin_cmds = np;
1327 #ifndef xxx
1328         treep = hashalloc(sh.var_tree,HASH_set,HASH_BUCKET,HASH_name,"vars",sh.var_tree?0:HASH_free,nv_unset,0);
1329         treep->root->flags |= HASH_BUCKET;
1330 #else
1331         treep = hashalloc(sh.var_tree,HASH_name,"vars",sh.var_tree?0:HASH_unset,nv_unset,0);
1332 #endif
1333         for(tp=name_vals;*tp->sh_name;tp++,np++)
1334         {
1335                 np->name = (char*)tp->sh_name;
1336                 np->nvenv = 0;
1337                 if(name_vals==(const struct shtable2*)shtab_builtins)
1338                 {
1339                         np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
1340                         if(*np->name=='/')
1341                         {
1342                                 np->nvenv = np->name;
1343                                 np->name = path_basename(np->name);
1344                         }
1345                 }
1346                 else
1347                         np->nvalue.cp = (char*)tp->sh_value;
1348                 nv_setattr(np,tp->sh_number);
1349                 if(nv_isattr(np,NV_INTEGER))
1350                         nv_setsize(np,10);
1351                 else
1352                         nv_setsize(np,0);
1353                 nv_link(treep,np);
1354         }
1355         hashset(treep,HASH_ALLOCATE);
1356         return(treep);
1357 }
1358
1359 /*
1360  * read in the process environment and set up name-value pairs
1361  * skip over items that are not name-value pairs
1362  */
1363
1364 static void env_init __PARAM__((void), ()){
1365         register char *cp;
1366         register Namval_t       *np;
1367         register char **ep=environ;
1368         register char *next=0;
1369         if(ep)
1370         {
1371                 while(cp= *ep++)
1372                 {
1373                         if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
1374                                 next = cp+4;
1375                         else if(np=nv_open(cp,sh.var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN))) 
1376                         {
1377                                 nv_onattr(np,NV_IMPORT);
1378                                 np->nvenv = cp;
1379                                 nv_close(np);
1380                         }
1381                 }
1382                 while(cp=next)
1383                 {
1384                         if(next = strchr(++cp,'='))
1385                                 *next = 0;
1386                         np = nv_search(cp+2,sh.var_tree,NV_ADD);
1387                         if(nv_isattr(np,NV_IMPORT|NV_EXPORT))
1388                                 nv_newattr(np,(unsigned)(cp[0]-' ')|NV_IMPORT|NV_EXPORT,cp[1]-' ');
1389                 }
1390         }
1391         if(nv_isattr(PWDNOD,NV_TAGGED))
1392         {
1393                 nv_offattr(PWDNOD,NV_TAGGED);
1394                 path_pwd(0);
1395         }
1396         if(cp = nv_getval(SHELLNOD))
1397         {
1398                 cp = path_basename(cp);
1399                 if(strmatch(cp,rsh_pattern))
1400                         sh_onoption(SH_RESTRICTED); /* restricted shell */
1401         }
1402         return;
1403 }
1404
1405 /*
1406  * terminate shell and free up the space
1407  */
1408 int sh_term __PARAM__((void), ()){
1409         sfdisc(sfstdin,SF_POPDISC);
1410         free((char*)sh.outbuff);
1411         stakset(NIL(char*),0);
1412         return(0);
1413 }
1414