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