2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: init.c /main/4 1995/11/17 15:16:52 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
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 *
33 * Copyright (c) 1995 AT&T Corp. *
34 * Unpublished & Not for Publication *
35 * All Rights Reserved *
37 * The copyright notice above does not evidence any *
38 * actual or intended publication of such source code *
40 * This software was created by the *
41 * Advanced Software Technology Department *
42 * AT&T Bell Laboratories *
44 * For further information contact *
45 * {research,attmail}!dgk *
47 ***************************************************************/
49 /* : : generated by proto : : */
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__ "C"
59 #define __PROTO__(x) x
61 #define __PARAM__(n,o) n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
74 #define __PROTO__(x) ()
75 #define __OTORP__(x) x
76 #define __PARAM__(n,o) o
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__ ...
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a) va_start(p,a)
92 #define __VA_START__(p,a) va_start(p)
98 #include "variables.h"
104 #include "FEATURE/time"
105 #include "FEATURE/dynamic"
106 #include "lexstates.h"
107 #include "FEATURE/locale"
108 #include "national.h"
110 #if _hdr_wchar && _lib_wctype && _lib_iswctype
111 /* on linux wchar.h can include FILE without stdio.h which clashes with sfio_t */
113 #ifndef __FILE_defined
114 #define __FILE_defined 1
119 # define isalpha(x) iswalpha(x)
121 # define isblank(x) iswblank(x)
128 iswblank __PARAM__((wint_t wc), (wc)) __OTORP__(wint_t wc;){
129 static int initialized;
135 wt = wctype("blank");
137 return(iswctype(wc, wt));
143 # define isblank(x) ((x)==' '||(x)=='\t')
150 # define LC_MESSAGES LC_ALL
151 # endif /* LC_MESSAGES */
152 #endif /* _hdr_locale */
154 #define RANDMASK 0x7fff
159 extern __MANGLE__ char **environ;
161 extern __MANGLE__ int Mt_certify;
164 static void env_init __PROTO__((void));
165 static void nv_init __PROTO__((void));
166 static Hashtab_t *inittree __PROTO__((const struct shtable2*));
168 static const char rsh_pattern[] = "@(rk|kr|r)sh";
169 static int rand_shift;
170 static Namval_t *ifsnp;
174 * Invalidate all path name bindings
176 static void rehash __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
177 nv_onattr(np,NV_NOALIAS);
181 * out of memory routine for stak routines
183 static char *nospace __PARAM__((int unused), (unused)) __OTORP__(int unused;){
185 error(ERROR_exit(3),e_nospace);
189 #ifdef SHOPT_MULTIBYTE
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;){
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);
199 #endif /* SHOPT_MULTIBYTE */
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)))
206 sh_offoption(SH_VI|SH_EMACS|SH_GMACS);
207 if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD)))))
209 /* turn on vi or emacs option if editor name is either*/
210 cp = path_basename(cp);
211 if(strmatch(cp,"*vi"))
213 if(strmatch(cp,"*macs"))
216 sh_onoption(SH_GMACS);
218 sh_onoption(SH_EMACS);
221 nv_putv(np, val, flags, fp);
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);
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))
237 nv_scan(sh.track_tree,rehash,NV_TAGGED,NV_TAGGED);
239 nv_putv(np, val, flags, fp);
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;){
246 nv_scan(sh.track_tree,rehash,NV_TAGGED,NV_TAGGED);
247 nv_putv(np, val, flags, fp);
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
271 static MsgStr allmsgs[] = {
274 {" [-n] [arg...]", 25, 4},
275 {" [arg...]", 25, 5},
276 {" [dir] [list]", 25, 6},
277 {" [job...]", 25, 7},
279 {" [name [pathname] ]", 25, 9},
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},
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},
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},
381 {"IO signal", 25, 112},
382 {"Illegal instruction", 25, 113},
383 {"Interrupt", 25, 114},
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},
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},
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},
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},
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},
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},
500 {"versions", 25, 231},
501 {"write to %d failed", 25, 232},
502 {"you have mail in $_", 25, 233},
503 {"zero byte", 25, 234},
506 #define _CLIENT_CAT_NAME "dtksh.cat"
508 #define _CLIENT_CAT_NAME "dtksh"
509 #endif /* __ultrix */
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.
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))
521 #include <nl_types.h>
523 static int localeChanged = 1;
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;)
528 nv_putv(np, val, flags, fp);
529 setlocale(LC_ALL, "");
533 /****************************************************************************
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.
548 **************************************************************************/
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().
557 int *LockKshFileDescriptors __PARAM__((void),())
563 fdList = (int *)malloc(sizeof(int) * 10);
564 for (i = 0; i < 10; i++)
567 if ((fd = open("/dev/null", O_RDONLY)) >= 0)
572 for (i = 1; i < 10; i++)
574 if ((newfd = dup(fd)) < 10)
590 void UnlockKshFileDescriptors __PARAM__((int *fdList), (fdList)) __OTORP__(int *fdList;)
594 for (i = 0; i < 10; i++)
596 if (fdList[i] != (-1))
600 free((char *)fdList);
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.
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;)
616 static nl_catd nlmsg_fd = (nl_catd)-1;
617 static char *lang = NULL;
621 int swappedNlsPath = 0;
623 static char pathBuf[1024] = {(char)'N', (char)'L', (char)'S', (char)'P',
624 (char)'A', (char)'T', (char)'H', (char)'='};
631 newLang = (char *) getenv ("LANG");
635 lang = strdup(newLang);
639 if (nlmsg_fd != (nl_catd)-1)
641 if(strcmp((oldPath = getenv("NLSPATH")), savedNlsPath) != 0)
644 pEqual = strchr(pathBuf, '=');
645 strcpy(pEqual + 1, savedNlsPath);
647 * Only call putenv if pathBuf isn't already holding NLSPATH
648 * in the environment.
650 if(oldPath != (pEqual + 1))
653 lockedFds = LockKshFileDescriptors();
654 nlmsg_fd = catopen(filename, 0);
655 UnlockKshFileDescriptors(lockedFds);
656 if(swappedNlsPath != 0)
659 pEqual = strchr(pathBuf, '=');
660 strcpy(pEqual + 1, oldPath);
661 if(oldPath != (pEqual + 1))
665 msg=catgets(nlmsg_fd,set,n,s);
670 * This function needs to be modified to handle international
671 * error message translations
673 static char *msg_translate __PARAM__((const char *message,int type), (message, type)) __OTORP__(const char *message;int type;)
675 int startIndex = 0, endIndex = sizeof(allmsgs)/sizeof(MsgStr) - 1,
676 midIndex, res, weFoundIt = 0;
678 if(type != 1) /* if it's not a shell message, don't translate */
679 return((char*)message);
681 while(startIndex != endIndex)
683 midIndex = (startIndex + endIndex) / 2;
684 if(midIndex == startIndex)
686 if((res = strcmp(allmsgs[startIndex].string, message)) == 0)
689 midIndex = startIndex;
694 if((res = strcmp(allmsgs[endIndex].string, message)) == 0)
701 /* we didn't find a match in the table */
707 if((res = strcmp(allmsgs[midIndex].string, message)) == 0)
710 break; /* we found it */
713 startIndex = midIndex;
719 return GETMESSAGE(allmsgs[midIndex].setNum, allmsgs[midIndex].msgNum, (char *)message);
721 return((char*)message);
725 # ifdef SHOPT_MULTIBYTE
726 void charsize_init __PARAM__((void), ()){
727 static char fc[3] = { 0301, ESS2, ESS3};
731 memset(buff,0301,MB_CUR_MAX);
735 if((n=mbtowc(&wc,buff,MB_CUR_MAX))>0)
737 if((int_charsize[i+1] = n-(i>0))>0)
738 int_charsize[i+5] = wcwidth(wc);
740 int_charsize[i+5] = 0;
744 # endif /* SHOPT_MULTIBYTE */
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;){
749 char *lc_all = nv_getval(LCALLNOD);
750 if(nv_name(np)==nv_name(LCTYPENOD))
752 else if(nv_name(np)==nv_name(LCMSGNOD))
754 else if(nv_name(np)==nv_name(LCCOLLNOD))
756 else if(nv_name(np)==nv_name(LCNUMNOD))
758 else if(nv_name(np)==nv_name(LANGNOD) && !lc_all)
762 if(type>=0 && type!=LC_ALL && !lc_all)
766 if(!setlocale(type,val?val:""))
768 error(0,e_badlocale,val);
772 if(type==LC_ALL || type==LC_CTYPE)
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)
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++)
799 if(state[0][c]==S_REG)
801 if(state[1][c]==S_REG)
803 if(state[2][c]==S_ERR)
805 if(state[3][c]==S_ERR)
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];
816 #ifdef SHOPT_MULTIBYTE
818 #endif /* SHOPT_MULTIBYTE */
820 if(type==LC_ALL || type==LC_MESSAGES)
821 error_info.translate = msg_translate;
822 nv_putv(np, val, flags, fp);
824 #endif /* _hdr_locale */
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;){
829 nv_putv(np, val, flags, fp);
833 * This is the lookup function for IFS
834 * It keeps the sh.ifstable up to date
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;
839 value = nv_getv(np,fp);
843 memset(sh.ifstable,0,(1<<CHAR_BIT));
846 #ifdef SHOPT_MULTIBYTE
847 while(n=mbtowc(0,cp,MB_CUR_MAX),c= *(unsigned char*)cp)
849 while(c= *(unsigned char*)cp++)
850 #endif /* SHOPT_MULTIBYTE */
852 #ifdef SHOPT_MULTIBYTE
856 sh.ifstable[c] = S_MBYTE;
859 #endif /* SHOPT_MULTIBYTE */
870 sh.ifstable[' '] = sh.ifstable['\t'] = S_SPACE;
871 sh.ifstable['\n'] = S_NL;
878 * these functions are used to get and set the SECONDS variable
880 #ifdef _lib_gettimeofday
881 # define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
884 # define dtime(tp) (((double)times(tp))/sh.lim.clk_tck)
885 # define gettimeofday(a,b)
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;
895 nv_stack(np, NIL(Namfun_t*));
903 gettimeofday(&tp,NIL(void *));
904 sec_offset = dtime(&tp)-d;
908 np->nvalue.dp = &sec_offset;
912 static char* get_seconds __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
916 gettimeofday(&tp,NIL(void *));
917 d = dtime(&tp)- *np->nvalue.dp;
918 return(sh_ftos(d,nv_size(np)));
921 static double nget_seconds __PARAM__((register Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(register Namval_t* np; Namfun_t *fp;){
924 gettimeofday(&tp,NIL(void *));
925 return(dtime(&tp)- *np->nvalue.dp);
929 * These three functions are used to get and set the RANDOM variable
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;
937 nv_stack(np, NIL(Namfun_t*));
945 srand((int)(n&RANDMASK));
948 np->nvalue.lp = &rand_last;
952 * get random number in range of 0 - 2**15
953 * never pick same number twice in a row
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;
959 cur = (rand()>>rand_shift)&RANDMASK;
961 *np->nvalue.lp = cur;
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));
971 * These three routines are for LINENO
973 static double nget_lineno __PARAM__((Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(Namval_t* np; Namfun_t *fp;){
975 if(error_info.line >0)
977 else if(error_info.context && error_info.context->line>0)
978 d = error_info.context->line;
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;){
989 nv_stack(np, NIL(Namfun_t*));
997 sh.st.firstline += nget_lineno(np,fp)+1-n;
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));
1005 static char* get_lastarg __PARAM__((Namval_t* np, Namfun_t *fp), (np, fp)) __OTORP__(Namval_t* np; Namfun_t *fp;){
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;){
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);
1018 nv_offattr(np,NV_NOFREE);
1020 sh.lastarg = strdup(val);
1027 * set or unset the mappings given a colon separated list of directories
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,':');
1036 if(lastp=strchr(newp,':'))
1038 mount((mode?newp:""),oldp,FS3D_VIEW,0);
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;){
1048 if(cp = nv_getval(np))
1051 vpath_set((char*)val,1);
1052 nv_putv(np,val,flags,fp);
1054 static const Namdisc_t VPATH_disc = { 0, put_vpath };
1055 static Namfun_t VPATH_init = { &VPATH_disc };
1056 #endif /* SHOPT_FS_3D */
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};
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 */
1087 static const Namdisc_t SYSTYPE_disc = { 0, put_systype };
1088 static Namfun_t SYSTYPE_init = { &SYSTYPEdisc};
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 */
1096 * This function will get called whenever a configuration parameter changes
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;){
1100 if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
1103 /* set directory in new universe */
1104 if(*(arg = path_pwd(0))=='/')
1106 /* clear out old tracked alias */
1108 stakputs(nv_getval(PATHNOD));
1110 nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
1116 * initialize the shell
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;
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]);
1131 sh.euserid=geteuid();
1132 sh.groupid=getgid();
1133 sh.egroupid=getegid();
1134 for(n=0;n < 10; n++)
1136 /* don't use lower bits when rand() generates large numbers */
1137 if(rand() > RANDMASK)
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;
1156 if(mount(".", NIL(char*),FS3D_GET|FS3D_VERSION,0) >= 0)
1158 #endif /* SHOPT_FS_3D */
1160 /* initialize signal handling */
1162 stakinstall(NIL(Stak_t*),nospace);
1163 /* set up memory for name-value pairs */
1165 /* read the environment */
1166 #ifdef SHOPT_MULTIBYTE
1168 #endif /* SHOPT_MULTIBYTE */
1170 nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
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 */
1182 name = path_basename(*argv);
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)
1198 sh.st.dolv=argv+(argc-1)-sh.st.dolc;
1199 sh.st.dolv[0] = argv[0];
1201 sh_onoption(SH_SFLAG);
1202 if(!sh_isoption(SH_SFLAG))
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)
1213 /* require sh -p to run setuid and/or setgid */
1214 if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID)
1216 setuid(sh.euserid=sh.userid);
1217 seTgid(sh.egroupid=sh.groupid);
1222 sh_onoption(SH_PRIVILEGED);
1225 #endif /* SHOPT_P_SUID */
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*/
1233 sh_offoption(SH_PRIVILEGED);
1234 sh.shname = strdup(sh.st.dolv[0]); /* shname for $0 in profiles */
1236 * return here for shell script execution
1237 * but not for parenthesis subshells
1239 error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */
1240 sh_offstate(SH_INIT);
1245 * reinitialize before executing a script
1247 void sh_reinit __PARAM__((char *argv[]), (argv)) __OTORP__(char *argv[];){
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);
1259 * set when creating a local variable of this name
1261 Namfun_t *nv_cover __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1262 register Namfun_t *nfp=0;
1265 else if(np==PATHNOD)
1267 else if(np==SHELLNOD)
1273 * Initialize the shell name and alias table
1275 static void nv_init __PARAM__((void), ()){
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);
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 */
1301 nv_stack(SYSTYPENOD, &SYSTYPE_init);
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);
1318 * initialize name-value pairs
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++)
1328 np = (Namval_t*)calloc(n,sizeof(Namval_t));
1330 sh.bltin_nodes = np;
1331 else if(name_vals==(const struct shtable2*)shtab_builtins)
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;
1337 treep = hashalloc(sh.var_tree,HASH_name,"vars",sh.var_tree?0:HASH_unset,nv_unset,0);
1339 for(tp=name_vals;*tp->sh_name;tp++,np++)
1341 np->name = (char*)tp->sh_name;
1343 if(name_vals==(const struct shtable2*)shtab_builtins)
1345 np->nvalue.bfp = ((struct shtable3*)tp)->sh_value;
1348 np->nvenv = np->name;
1349 np->name = path_basename(np->name);
1353 np->nvalue.cp = (char*)tp->sh_value;
1354 nv_setattr(np,tp->sh_number);
1355 if(nv_isattr(np,NV_INTEGER))
1361 hashset(treep,HASH_ALLOCATE);
1366 * read in the process environment and set up name-value pairs
1367 * skip over items that are not name-value pairs
1370 static void env_init __PARAM__((void), ()){
1372 register Namval_t *np;
1373 register char **ep=environ;
1374 register char *next=0;
1379 if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]=='=')
1381 else if(np=nv_open(cp,sh.var_tree,(NV_EXPORT|NV_IDENT|NV_ASSIGN)))
1383 nv_onattr(np,NV_IMPORT);
1390 if(next = strchr(++cp,'='))
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]-' ');
1397 if(nv_isattr(PWDNOD,NV_TAGGED))
1399 nv_offattr(PWDNOD,NV_TAGGED);
1402 if(cp = nv_getval(SHELLNOD))
1404 cp = path_basename(cp);
1405 if(strmatch(cp,rsh_pattern))
1406 sh_onoption(SH_RESTRICTED); /* restricted shell */
1412 * terminate shell and free up the space
1414 int sh_term __PARAM__((void), ()){
1415 sfdisc(sfstdin,SF_POPDISC);
1416 free((char*)sh.outbuff);
1417 stakset(NIL(char*),0);