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