Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/init.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
*
23
* Shell initialization
24
*
25
* David Korn
26
* AT&T Labs
27
*
28
*/
29
30
#include "defs.h"
31
#include <stak.h>
32
#include <ccode.h>
33
#include <pwd.h>
34
#include <tmx.h>
35
#include <regex.h>
36
#include "variables.h"
37
#include "path.h"
38
#include "fault.h"
39
#include "name.h"
40
#include "edit.h"
41
#include "jobs.h"
42
#include "io.h"
43
#include "shlex.h"
44
#include "builtins.h"
45
#include "FEATURE/time"
46
#include "FEATURE/dynamic"
47
#include "FEATURE/externs"
48
#include "lexstates.h"
49
#include "version.h"
50
51
#if _hdr_wctype
52
#include <ast_wchar.h>
53
#include <wctype.h>
54
#endif
55
#if !_typ_wctrans_t
56
#undef wctrans_t
57
#define wctrans_t sh_wctrans_t
58
typedef long wctrans_t;
59
#endif
60
#if !_lib_wctrans
61
#undef wctrans
62
#define wctrans sh_wctrans
63
static wctrans_t wctrans(const char *name)
64
{
65
if(strcmp(name,e_tolower)==0)
66
return(1);
67
else if(strcmp(name,e_toupper)==0)
68
return(2);
69
return(0);
70
}
71
#endif
72
#if !_lib_towctrans
73
#undef towctrans
74
#define towctrans sh_towctrans
75
static int towctrans(int c, wctrans_t t)
76
{
77
if(t==1 && isupper(c))
78
c = tolower(c);
79
else if(t==2 && islower(c))
80
c = toupper(c);
81
return(c);
82
}
83
#endif
84
85
char e_version[] = "\n@(#)$Id: Version "
86
#if SHOPT_AUDIT
87
#define ATTRS 1
88
"A"
89
#endif
90
#if SHOPT_BASH
91
#define ATTRS 1
92
"B"
93
#endif
94
#if SHOPT_COSHELL
95
#define ATTRS 1
96
"J"
97
#else
98
#if SHOPT_BGX
99
#define ATTRS 1
100
"j"
101
#endif
102
#endif
103
#if SHOPT_ACCT
104
#define ATTRS 1
105
"L"
106
#endif
107
#if SHOPT_MULTIBYTE
108
#define ATTRS 1
109
"M"
110
#endif
111
#if SHOPT_PFSH && _hdr_exec_attr
112
#define ATTRS 1
113
"P"
114
#endif
115
#if SHOPT_REGRESS
116
#define ATTRS 1
117
"R"
118
#endif
119
#if ATTRS
120
" "
121
#endif
122
SH_RELEASE " $\0\n";
123
124
#if SHOPT_BASH
125
extern void bash_init(Shell_t*,int);
126
#endif
127
128
#define RANDMASK 0x7fff
129
130
#ifndef ARG_MAX
131
# define ARG_MAX (1*1024*1024)
132
#endif
133
#ifndef CHILD_MAX
134
# define CHILD_MAX (1*1024)
135
#endif
136
#ifndef CLK_TCK
137
# define CLK_TCK 60
138
#endif /* CLK_TCK */
139
140
#ifndef environ
141
extern char **environ;
142
#endif
143
144
#undef getconf
145
#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
146
147
struct seconds
148
{
149
Namfun_t hdr;
150
Shell_t *sh;
151
};
152
153
struct rand
154
{
155
Namfun_t hdr;
156
Shell_t *sh;
157
int32_t rand_last;
158
};
159
160
struct ifs
161
{
162
Namfun_t hdr;
163
Namval_t *ifsnp;
164
};
165
166
struct match
167
{
168
Namfun_t hdr;
169
const char *v;
170
char *val;
171
char *rval[2];
172
regoff_t *match;
173
char node[NV_MINSZ+sizeof(char*)];
174
regoff_t first;
175
int vsize;
176
int nmatch;
177
int index;
178
int lastsub[2];
179
};
180
181
typedef struct _init_
182
{
183
Shell_t *sh;
184
#if SHOPT_FS_3D
185
Namfun_t VPATH_init;
186
#endif /* SHOPT_FS_3D */
187
struct ifs IFS_init;
188
Namfun_t PATH_init;
189
Namfun_t FPATH_init;
190
Namfun_t CDPATH_init;
191
Namfun_t SHELL_init;
192
Namfun_t ENV_init;
193
Namfun_t VISUAL_init;
194
Namfun_t EDITOR_init;
195
Namfun_t HISTFILE_init;
196
Namfun_t HISTSIZE_init;
197
Namfun_t OPTINDEX_init;
198
struct seconds SECONDS_init;
199
struct rand RAND_init;
200
Namfun_t LINENO_init;
201
Namfun_t L_ARG_init;
202
Namfun_t SH_VERSION_init;
203
struct match SH_MATCH_init;
204
Namfun_t SH_MATH_init;
205
#if SHOPT_COSHELL
206
Namfun_t SH_JOBPOOL_init;
207
#endif /* SHOPT_COSHELL */
208
#ifdef _hdr_locale
209
Namfun_t LC_TYPE_init;
210
Namfun_t LC_NUM_init;
211
Namfun_t LC_COLL_init;
212
Namfun_t LC_MSG_init;
213
Namfun_t LC_ALL_init;
214
Namfun_t LANG_init;
215
#endif /* _hdr_locale */
216
} Init_t;
217
218
static Init_t *ip;
219
static int lctype;
220
static int nbltins;
221
static void env_init(Shell_t*);
222
static Init_t *nv_init(Shell_t*);
223
static Dt_t *inittree(Shell_t*,const struct shtable2*);
224
static int shlvl;
225
226
#ifdef _WINIX
227
# define EXE "?(.exe)"
228
#else
229
# define EXE
230
#endif
231
232
static int rand_shift;
233
234
235
/*
236
* Invalidate all path name bindings
237
*/
238
static void rehash(register Namval_t *np,void *data)
239
{
240
NOT_USED(data);
241
nv_onattr(np,NV_NOALIAS);
242
}
243
244
/*
245
* out of memory routine for stak routines
246
*/
247
static char *nospace(int unused)
248
{
249
NOT_USED(unused);
250
errormsg(SH_DICT,ERROR_exit(3),e_nospace);
251
return(NIL(char*));
252
}
253
254
/* Trap for VISUAL and EDITOR variables */
255
static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
256
{
257
register const char *cp, *name=nv_name(np);
258
register int newopt=0;
259
Shell_t *shp = nv_shell(np);
260
if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD)))
261
goto done;
262
if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD)))))
263
goto done;
264
/* turn on vi or emacs option if editor name is either*/
265
cp = path_basename(cp);
266
if(strmatch(cp,"*[Vv][Ii]*"))
267
newopt=SH_VI;
268
else if(strmatch(cp,"*gmacs*"))
269
newopt=SH_GMACS;
270
else if(strmatch(cp,"*macs*"))
271
newopt=SH_EMACS;
272
if(newopt)
273
{
274
sh_offoption(SH_VI);
275
sh_offoption(SH_EMACS);
276
sh_offoption(SH_GMACS);
277
sh_onoption(newopt);
278
}
279
done:
280
nv_putv(np, val, flags, fp);
281
}
282
283
/* Trap for HISTFILE and HISTSIZE variables */
284
static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
285
{
286
Shell_t *shp = nv_shell(np);
287
void *histopen = shp->gd->hist_ptr;
288
char *cp;
289
if(val && histopen)
290
{
291
if(np==HISTFILE && (cp=nv_getval(np)) && strcmp(val,cp)==0)
292
return;
293
if(np==HISTSIZE && sh_arith(shp,val)==nv_getnum(HISTSIZE))
294
return;
295
hist_close(shp->gd->hist_ptr);
296
}
297
nv_putv(np, val, flags, fp);
298
if(histopen)
299
{
300
if(val)
301
sh_histinit(shp);
302
else
303
hist_close(histopen);
304
}
305
}
306
307
/* Trap for OPTINDEX */
308
static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp)
309
{
310
Shell_t *shp = nv_shell(np);
311
shp->st.opterror = shp->st.optchar = 0;
312
nv_putv(np, val, flags, fp);
313
if(!val)
314
nv_disc(np,fp,NV_POP);
315
}
316
317
static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp)
318
{
319
return((Sfdouble_t)*np->nvalue.lp);
320
}
321
322
static Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
323
{
324
Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t));
325
memcpy((void*)dp,(void*)fp,sizeof(Namfun_t));
326
mp->nvalue.lp = np->nvalue.lp;
327
dp->nofree = 0;
328
return(dp);
329
}
330
331
332
/* Trap for restricted variables FPATH, PATH, SHELL, ENV */
333
static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
334
{
335
Shell_t *shp = nv_shell(np);
336
int path_scoped = 0, fpath_scoped=0;
337
Pathcomp_t *pp;
338
char *name = nv_name(np);
339
if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED))
340
errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
341
if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
342
{
343
nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
344
if(path_scoped && !val)
345
val = PATHNOD->nvalue.cp;
346
}
347
if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0)
348
return;
349
if(np==FPATHNOD || (fpath_scoped=(strcmp(name,FPATHNOD->nvname)==0)))
350
shp->pathlist = (void*)path_unsetfpath(shp);
351
nv_putv(np, val, flags, fp);
352
shp->universe = 0;
353
if(shp->pathlist)
354
{
355
val = np->nvalue.cp;
356
if(np==PATHNOD || path_scoped)
357
pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_PATH);
358
else if(val && (np==FPATHNOD || fpath_scoped))
359
pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->pathlist,val,PATH_FPATH);
360
else
361
return;
362
if(shp->pathlist = (void*)pp)
363
pp->shp = shp;
364
if(!val && (flags&NV_NOSCOPE))
365
{
366
Namval_t *mp = dtsearch(shp->var_tree,np);
367
if(mp && (val=nv_getval(mp)))
368
nv_putval(mp,val,NV_RDONLY);
369
}
370
#if 0
371
sfprintf(sfstderr,"%d: name=%s val=%s\n",getpid(),name,val);
372
path_dump((Pathcomp_t*)shp->pathlist);
373
#endif
374
}
375
}
376
377
static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
378
{
379
Pathcomp_t *pp;
380
Shell_t *shp = nv_shell(np);
381
nv_putv(np, val, flags, fp);
382
if(!shp->cdpathlist)
383
return;
384
val = np->nvalue.cp;
385
pp = (void*)path_addpath(shp,(Pathcomp_t*)shp->cdpathlist,val,PATH_CDPATH);
386
if(shp->cdpathlist = (void*)pp)
387
pp->shp = shp;
388
}
389
390
#ifdef _hdr_locale
391
/*
392
* This function needs to be modified to handle international
393
* error message translations
394
*/
395
#if ERROR_VERSION >= 20000101L
396
static char* msg_translate(const char* catalog, const char* message)
397
{
398
NOT_USED(catalog);
399
return((char*)message);
400
}
401
#else
402
static char* msg_translate(const char* message, int type)
403
{
404
NOT_USED(type);
405
return((char*)message);
406
}
407
#endif
408
409
/* Trap for LC_ALL, LC_CTYPE, LC_MESSAGES, LC_COLLATE and LANG */
410
static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp)
411
{
412
Shell_t *shp = nv_shell(np);
413
int type;
414
char *name = nv_name(np);
415
if(name==(LCALLNOD)->nvname)
416
type = LC_ALL;
417
else if(name==(LCTYPENOD)->nvname)
418
type = LC_CTYPE;
419
else if(name==(LCMSGNOD)->nvname)
420
type = LC_MESSAGES;
421
else if(name==(LCCOLLNOD)->nvname)
422
type = LC_COLLATE;
423
else if(name==(LCNUMNOD)->nvname)
424
type = LC_NUMERIC;
425
#ifdef LC_LANG
426
else if(name==(LANGNOD)->nvname)
427
type = LC_LANG;
428
#else
429
#define LC_LANG LC_ALL
430
else if(name==(LANGNOD)->nvname && (!(name=nv_getval(LCALLNOD)) || !*name))
431
type = LC_LANG;
432
#endif
433
else
434
type= -1;
435
if(!sh_isstate(SH_INIT) && (type>=0 || type==LC_ALL || type==LC_LANG))
436
{
437
char* r;
438
#ifdef AST_LC_setenv
439
ast.locale.set |= AST_LC_setenv;
440
#endif
441
r = setlocale(type,val?val:"");
442
#ifdef AST_LC_setenv
443
ast.locale.set ^= AST_LC_setenv;
444
#endif
445
if(!r && val)
446
{
447
if(!sh_isstate(SH_INIT) || shp->login_sh==0)
448
errormsg(SH_DICT,0,e_badlocale,val);
449
return;
450
}
451
}
452
nv_putv(np, val, flags, fp);
453
if(CC_NATIVE!=CC_ASCII && (type==LC_ALL || type==LC_LANG || type==LC_CTYPE))
454
{
455
if(sh_lexstates[ST_BEGIN]!=sh_lexrstates[ST_BEGIN])
456
free((void*)sh_lexstates[ST_BEGIN]);
457
lctype++;
458
if(ast.locale.set&(1<<AST_LC_CTYPE))
459
{
460
register int c;
461
char *state[4];
462
sh_lexstates[ST_BEGIN] = state[0] = (char*)malloc(4*(1<<CHAR_BIT));
463
memcpy(state[0],sh_lexrstates[ST_BEGIN],(1<<CHAR_BIT));
464
sh_lexstates[ST_NAME] = state[1] = state[0] + (1<<CHAR_BIT);
465
memcpy(state[1],sh_lexrstates[ST_NAME],(1<<CHAR_BIT));
466
sh_lexstates[ST_DOL] = state[2] = state[1] + (1<<CHAR_BIT);
467
memcpy(state[2],sh_lexrstates[ST_DOL],(1<<CHAR_BIT));
468
sh_lexstates[ST_BRACE] = state[3] = state[2] + (1<<CHAR_BIT);
469
memcpy(state[3],sh_lexrstates[ST_BRACE],(1<<CHAR_BIT));
470
for(c=0; c<(1<<CHAR_BIT); c++)
471
{
472
if(state[0][c]!=S_REG)
473
continue;
474
if(state[2][c]!=S_ERR)
475
continue;
476
if(isblank(c))
477
{
478
state[0][c]=0;
479
state[1][c]=S_BREAK;
480
state[2][c]=S_BREAK;
481
continue;
482
}
483
if(!isalpha(c))
484
continue;
485
state[0][c]=S_NAME;
486
if(state[1][c]==S_REG)
487
state[1][c]=0;
488
state[2][c]=S_ALP;
489
if(state[3][c]==S_ERR)
490
state[3][c]=0;
491
}
492
}
493
else
494
{
495
sh_lexstates[ST_BEGIN]=(char*)sh_lexrstates[ST_BEGIN];
496
sh_lexstates[ST_NAME]=(char*)sh_lexrstates[ST_NAME];
497
sh_lexstates[ST_DOL]=(char*)sh_lexrstates[ST_DOL];
498
sh_lexstates[ST_BRACE]=(char*)sh_lexrstates[ST_BRACE];
499
}
500
}
501
#if ERROR_VERSION < 20000101L
502
if(type==LC_ALL || type==LC_MESSAGES)
503
error_info.translate = msg_translate;
504
#endif
505
}
506
#endif /* _hdr_locale */
507
508
/* Trap for IFS assignment and invalidates state table */
509
static void put_ifs(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
510
{
511
register struct ifs *ip = (struct ifs*)fp;
512
ip->ifsnp = 0;
513
if(!val)
514
{
515
fp = nv_stack(np, NIL(Namfun_t*));
516
if(fp && !fp->nofree)
517
{
518
free((void*)fp);
519
fp = 0;
520
}
521
}
522
if(val != np->nvalue.cp)
523
nv_putv(np, val, flags, fp);
524
if(!val)
525
{
526
if(fp)
527
fp->next = np->nvfun;
528
np->nvfun = fp;
529
}
530
}
531
532
/*
533
* This is the lookup function for IFS
534
* It keeps the sh.ifstable up to date
535
*/
536
static char* get_ifs(register Namval_t* np, Namfun_t *fp)
537
{
538
register struct ifs *ip = (struct ifs*)fp;
539
register char *cp, *value;
540
register int c,n;
541
register Shell_t *shp = nv_shell(np);
542
value = nv_getv(np,fp);
543
if(np!=ip->ifsnp)
544
{
545
ip->ifsnp = np;
546
memset(shp->ifstable,0,(1<<CHAR_BIT));
547
if(cp=value)
548
{
549
#if SHOPT_MULTIBYTE
550
while(n=mbsize(cp),c= *(unsigned char*)cp)
551
#else
552
while(c= *(unsigned char*)cp++)
553
#endif /* SHOPT_MULTIBYTE */
554
{
555
#if SHOPT_MULTIBYTE
556
cp++;
557
if(n>1)
558
{
559
cp += (n-1);
560
shp->ifstable[c] = S_MBYTE;
561
continue;
562
}
563
#endif /* SHOPT_MULTIBYTE */
564
n = S_DELIM;
565
if(c== *cp)
566
cp++;
567
else if(c=='\n')
568
n = S_NL;
569
else if(isspace(c))
570
n = S_SPACE;
571
shp->ifstable[c] = n;
572
}
573
}
574
else
575
{
576
shp->ifstable[' '] = shp->ifstable['\t'] = S_SPACE;
577
shp->ifstable['\n'] = S_NL;
578
}
579
}
580
return(value);
581
}
582
583
/*
584
* these functions are used to get and set the SECONDS variable
585
*/
586
#ifdef timeofday
587
# define dtime(tp) ((double)((tp)->tv_sec)+1e-6*((double)((tp)->tv_usec)))
588
# define tms timeval
589
#else
590
# define dtime(tp) (((double)times(tp))/shgd->lim.clk_tck)
591
# define timeofday(a)
592
#endif
593
594
static void put_seconds(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
595
{
596
double d;
597
struct tms tp;
598
if(!val)
599
{
600
nv_putv(np, val, flags, fp);
601
fp = nv_stack(np, NIL(Namfun_t*));
602
if(fp && !fp->nofree)
603
free((void*)fp);
604
return;
605
}
606
if(!np->nvalue.dp)
607
{
608
nv_setsize(np,3);
609
nv_onattr(np,NV_DOUBLE);
610
np->nvalue.dp = new_of(double,0);
611
}
612
nv_putv(np, val, flags, fp);
613
d = *np->nvalue.dp;
614
timeofday(&tp);
615
*np->nvalue.dp = dtime(&tp)-d;
616
}
617
618
static char* get_seconds(register Namval_t* np, Namfun_t *fp)
619
{
620
Shell_t *shp = nv_shell(np);
621
register int places = nv_size(np);
622
struct tms tp;
623
double d, offset = (np->nvalue.dp?*np->nvalue.dp:0);
624
NOT_USED(fp);
625
timeofday(&tp);
626
d = dtime(&tp)- offset;
627
sfprintf(shp->strbuf,"%.*f",places,d);
628
return(sfstruse(shp->strbuf));
629
}
630
631
static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp)
632
{
633
struct tms tp;
634
double offset = (np->nvalue.dp?*np->nvalue.dp:0);
635
NOT_USED(fp);
636
timeofday(&tp);
637
return(dtime(&tp)- offset);
638
}
639
640
/*
641
* These three functions are used to get and set the RANDOM variable
642
*/
643
static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
644
{
645
struct rand *rp = (struct rand*)fp;
646
register long n;
647
if(!val)
648
{
649
fp = nv_stack(np, NIL(Namfun_t*));
650
if(fp && !fp->nofree)
651
free((void*)fp);
652
_nv_unset(np,0);
653
return;
654
}
655
if(flags&NV_INTEGER)
656
n = *(double*)val;
657
else
658
n = sh_arith(rp->sh,val);
659
srand((int)(n&RANDMASK));
660
rp->rand_last = -1;
661
if(!np->nvalue.lp)
662
np->nvalue.lp = &rp->rand_last;
663
}
664
665
/*
666
* get random number in range of 0 - 2**15
667
* never pick same number twice in a row
668
*/
669
static Sfdouble_t nget_rand(register Namval_t* np, Namfun_t *fp)
670
{
671
register long cur, last= *np->nvalue.lp;
672
NOT_USED(fp);
673
do
674
cur = (rand()>>rand_shift)&RANDMASK;
675
while(cur==last);
676
*np->nvalue.lp = cur;
677
return((Sfdouble_t)cur);
678
}
679
680
static char* get_rand(register Namval_t* np, Namfun_t *fp)
681
{
682
register long n = nget_rand(np,fp);
683
return(fmtbase(n, 10, 0));
684
}
685
686
/*
687
* These three routines are for LINENO
688
*/
689
static Sfdouble_t nget_lineno(Namval_t* np, Namfun_t *fp)
690
{
691
double d=1;
692
if(error_info.line >0)
693
d = error_info.line;
694
else if(error_info.context && error_info.context->line>0)
695
d = error_info.context->line;
696
NOT_USED(np);
697
NOT_USED(fp);
698
return(d);
699
}
700
701
static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
702
{
703
register long n;
704
Shell_t *shp = nv_shell(np);
705
if(!val)
706
{
707
fp = nv_stack(np, NIL(Namfun_t*));
708
if(fp && !fp->nofree)
709
free((void*)fp);
710
_nv_unset(np,0);
711
return;
712
}
713
if(flags&NV_INTEGER)
714
n = *(double*)val;
715
else
716
n = sh_arith(shp,val);
717
shp->st.firstline += nget_lineno(np,fp)+1-n;
718
}
719
720
static char* get_lineno(register Namval_t* np, Namfun_t *fp)
721
{
722
register long n = nget_lineno(np,fp);
723
return(fmtbase(n, 10, 0));
724
}
725
726
static char* get_lastarg(Namval_t* np, Namfun_t *fp)
727
{
728
Shell_t *shp = nv_shell(np);
729
char *cp;
730
int pid;
731
if(sh_isstate(SH_INIT) && (cp=shp->lastarg) && *cp=='*' && (pid=strtol(cp+1,&cp,10)) && *cp=='*')
732
nv_putval(np,(pid==shp->gd->ppid?cp+1:0),0);
733
return(shp->lastarg);
734
}
735
736
static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp)
737
{
738
Shell_t *shp = nv_shell(np);
739
if(flags&NV_INTEGER)
740
{
741
sfprintf(shp->strbuf,"%.*g",12,*((double*)val));
742
val = sfstruse(shp->strbuf);
743
}
744
if(val)
745
val = strdup(val);
746
if(shp->lastarg && !nv_isattr(np,NV_NOFREE))
747
free((void*)shp->lastarg);
748
else
749
nv_offattr(np,NV_NOFREE);
750
shp->lastarg = (char*)val;
751
nv_offattr(np,NV_EXPORT);
752
np->nvenv = 0;
753
}
754
755
static int hasgetdisc(register Namfun_t *fp)
756
{
757
while(fp && !fp->disc->getnum && !fp->disc->getval)
758
fp = fp->next;
759
return(fp!=0);
760
}
761
762
/*
763
* store the most recent value for use in .sh.match
764
* treat .sh.match as a two dimensional array
765
*/
766
void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t match[],int index)
767
{
768
struct match *mp = &ip->SH_MATCH_init;
769
Namval_t *np = nv_namptr(mp->node,0);
770
register int i,n,x, savesub=shp->subshell;
771
Namarr_t *ap = nv_arrayptr(SH_MATCHNOD);
772
shp->subshell = 0;
773
#ifndef SHOPT_2DMATCH
774
index = 0;
775
#else
776
if(index==0)
777
#endif /* SHOPT_2DMATCH */
778
{
779
if(ap->hdr.next != &mp->hdr)
780
{
781
free((void*)ap);
782
ap = nv_arrayptr(np);
783
SH_MATCHNOD->nvfun = &ap->hdr;
784
}
785
if(ap)
786
{
787
ap->nelem &= ~ARRAY_SCAN;
788
i = array_elem(ap);
789
ap->nelem++;
790
while(--i>= 0)
791
{
792
nv_putsub(SH_MATCHNOD, (char*)0,i);
793
_nv_unset(SH_MATCHNOD,NV_RDONLY);
794
}
795
ap->nelem--;
796
}
797
if(!nv_hasdisc(SH_MATCHNOD,mp->hdr.disc))
798
nv_disc(SH_MATCHNOD,&mp->hdr,NV_LAST);
799
if(nmatch)
800
nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL|ARRAY_SETSUB);
801
ap = nv_arrayptr(SH_MATCHNOD);
802
ap->nelem = mp->nmatch = nmatch;
803
mp->v = v;
804
mp->first = match[0];
805
}
806
#ifdef SHOPT_2DMATCH
807
else
808
{
809
if(index==1)
810
{
811
np->nvalue.cp = Empty;
812
np->nvfun = SH_MATCHNOD->nvfun;
813
nv_onattr(np,NV_NOFREE|NV_ARRAY);
814
SH_MATCHNOD->nvfun = 0;
815
for(i=0; i < mp->nmatch; i++)
816
{
817
nv_putsub(SH_MATCHNOD, (char*)0, i);
818
nv_arraychild(SH_MATCHNOD, np,0);
819
}
820
if(ap = nv_arrayptr(SH_MATCHNOD))
821
ap->nelem = mp->nmatch;
822
}
823
ap = nv_arrayptr(np);
824
nv_putsub(np, NIL(char*), index|ARRAY_FILL|ARRAY_SETSUB);
825
}
826
#endif /* SHOPT_2DMATCH */
827
shp->subshell = savesub;
828
index *= 2*mp->nmatch;
829
if(mp->nmatch)
830
{
831
for(n=mp->first+(mp->v-v),vsize=0,i=0; i < 2*nmatch; i++)
832
{
833
if(match[i]>=0 && (match[i] - n) > vsize)
834
vsize = match[i] -n;
835
}
836
i = (index+2*mp->nmatch)*sizeof(match[0]);
837
if((i+vsize) >= mp->vsize)
838
{
839
if(mp->vsize)
840
mp->match = (int*)realloc(mp->match,i+vsize+1);
841
else
842
mp->match = (int*)malloc(i+vsize+1);
843
mp->vsize = i+vsize+1;
844
}
845
mp->val = ((char*)mp->match)+i;
846
memcpy(mp->match+index,match,nmatch*2*sizeof(match[0]));
847
for(x=0,i=0; i < 2*nmatch; i++)
848
{
849
if(match[i]>=0)
850
mp->match[index+i] -= n;
851
else
852
x=1;
853
854
}
855
ap->nelem -= x;
856
while(i < 2*mp->nmatch)
857
mp->match[index+i++] = -1;
858
memcpy(mp->val,v+n,vsize);
859
mp->val[vsize] = 0;
860
mp->lastsub[0] = mp->lastsub[1] = -1;
861
}
862
}
863
864
#define array_scan(np) ((nv_arrayptr(np)->nelem&ARRAY_SCAN))
865
866
static char* get_match(register Namval_t* np, Namfun_t *fp)
867
{
868
struct match *mp = (struct match*)fp;
869
int sub,sub2=0,n,i =!mp->index;
870
char *val;
871
sub = nv_aindex(SH_MATCHNOD);
872
if(np!=SH_MATCHNOD)
873
sub2 = nv_aindex(np);
874
if(sub>=mp->nmatch)
875
return(0);
876
if(sub2>0)
877
sub += sub2*mp->nmatch;
878
if(sub==mp->lastsub[!i])
879
return(mp->rval[!i]);
880
else if(sub==mp->lastsub[i])
881
return(mp->rval[i]);
882
n = mp->match[2*sub+1]-mp->match[2*sub];
883
if(n<=0)
884
return(mp->match[2*sub]<0?Empty:"");
885
val = mp->val+mp->match[2*sub];
886
if(mp->val[mp->match[2*sub+1]]==0)
887
return(val);
888
mp->index = i;
889
if(mp->rval[i])
890
{
891
free((void*)mp->rval[i]);
892
mp->rval[i] = 0;
893
}
894
mp->rval[i] = (char*)malloc(n+1);
895
mp->lastsub[i] = sub;
896
memcpy(mp->rval[i],val,n);
897
mp->rval[i][n] = 0;
898
return(mp->rval[i]);
899
}
900
901
static const Namdisc_t SH_MATCH_disc = { sizeof(struct match), 0, get_match };
902
903
static char* get_version(register Namval_t* np, Namfun_t *fp)
904
{
905
return(nv_getv(np,fp));
906
}
907
908
static Sfdouble_t nget_version(register Namval_t* np, Namfun_t *fp)
909
{
910
register const char *cp = e_version + strlen(e_version)-10;
911
register int c;
912
Sflong_t t = 0;
913
NOT_USED(fp);
914
915
while (c = *cp++)
916
if (c >= '0' && c <= '9')
917
{
918
t *= 10;
919
t += c - '0';
920
}
921
return((Sfdouble_t)t);
922
}
923
924
static const Namdisc_t SH_VERSION_disc = { 0, 0, get_version, nget_version };
925
926
#if SHOPT_FS_3D
927
/*
928
* set or unset the mappings given a colon separated list of directories
929
*/
930
static void vpath_set(char *str, int mode)
931
{
932
register char *lastp, *oldp=str, *newp=strchr(oldp,':');
933
if(!shgd->lim.fs3d)
934
return;
935
while(newp)
936
{
937
*newp++ = 0;
938
if(lastp=strchr(newp,':'))
939
*lastp = 0;
940
mount((mode?newp:""),oldp,FS3D_VIEW,0);
941
newp[-1] = ':';
942
oldp = newp;
943
newp=lastp;
944
}
945
}
946
947
/* catch vpath assignments */
948
static void put_vpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
949
{
950
register char *cp;
951
if(cp = nv_getval(np))
952
vpath_set(cp,0);
953
if(val)
954
vpath_set((char*)val,1);
955
nv_putv(np,val,flags,fp);
956
}
957
static const Namdisc_t VPATH_disc = { 0, put_vpath };
958
static Namfun_t VPATH_init = { &VPATH_disc, 1 };
959
#endif /* SHOPT_FS_3D */
960
961
962
static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs };
963
const Namdisc_t RESTRICTED_disc = { sizeof(Namfun_t), put_restricted };
964
static const Namdisc_t CDPATH_disc = { sizeof(Namfun_t), put_cdpath };
965
static const Namdisc_t EDITOR_disc = { sizeof(Namfun_t), put_ed };
966
static const Namdisc_t HISTFILE_disc = { sizeof(Namfun_t), put_history };
967
static const Namdisc_t OPTINDEX_disc = { sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex };
968
static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds };
969
static const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand };
970
static const Namdisc_t LINENO_disc = { sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno };
971
static const Namdisc_t L_ARG_disc = { sizeof(Namfun_t), put_lastarg, get_lastarg };
972
973
974
#define MAX_MATH_ARGS 3
975
976
static char *name_math(Namval_t *np, Namfun_t *fp)
977
{
978
Shell_t *shp = sh_getinterp();
979
sfprintf(shp->strbuf,".sh.math.%s",np->nvname);
980
return(sfstruse(shp->strbuf));
981
}
982
983
static const Namdisc_t math_child_disc =
984
{
985
0,0,0,0,0,0,0,
986
name_math
987
};
988
989
static Namfun_t math_child_fun =
990
{
991
&math_child_disc, 1, 0, sizeof(Namfun_t)
992
};
993
994
static void math_init(Shell_t *shp)
995
{
996
Namval_t *np;
997
char *name;
998
int i;
999
shp->mathnodes = (char*)calloc(1,MAX_MATH_ARGS*(NV_MINSZ+5));
1000
name = shp->mathnodes+MAX_MATH_ARGS*NV_MINSZ;
1001
for(i=0; i < MAX_MATH_ARGS; i++)
1002
{
1003
np = nv_namptr(shp->mathnodes,i);
1004
np->nvfun = &math_child_fun;
1005
memcpy(name,"arg",3);
1006
name[3] = '1'+i;
1007
np->nvname = name;
1008
name+=5;
1009
nv_onattr(np,NV_MINIMAL|NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
1010
}
1011
}
1012
1013
static Namval_t *create_math(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1014
{
1015
Shell_t *shp = nv_shell(np);
1016
if(!name)
1017
return(SH_MATHNOD);
1018
if(name[0]!='a' || name[1]!='r' || name[2]!='g' || name[4] || !isdigit(name[3]) || (name[3]=='0' || (name[3]-'0')>MAX_MATH_ARGS))
1019
return(0);
1020
fp->last = (char*)&name[4];
1021
return(nv_namptr(shp->mathnodes,name[3]-'1'));
1022
}
1023
1024
static char* get_math(register Namval_t* np, Namfun_t *fp)
1025
{
1026
Shell_t *shp = nv_shell(np);
1027
Namval_t *mp,fake;
1028
char *val;
1029
int first=0;
1030
fake.nvname = ".sh.math.";
1031
mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1032
while(mp=(Namval_t*)dtnext(shp->fun_tree,mp))
1033
{
1034
if(memcmp(mp->nvname,".sh.math.",9))
1035
break;
1036
if(first++)
1037
sfputc(shp->strbuf,' ');
1038
sfputr(shp->strbuf,mp->nvname+9,-1);
1039
}
1040
val = sfstruse(shp->strbuf);
1041
return(val);
1042
1043
}
1044
1045
static char *setdisc_any(Namval_t *np, const char *event, Namval_t *action, Namfun_t *fp)
1046
{
1047
Shell_t *shp=nv_shell(np);
1048
Namval_t *mp,fake;
1049
char *name;
1050
int getname=0, off=staktell();
1051
fake.nvname = nv_name(np);
1052
if(!event)
1053
{
1054
if(!action)
1055
{
1056
mp = (Namval_t*)dtprev(shp->fun_tree,&fake);
1057
return((char*)dtnext(shp->fun_tree,mp));
1058
}
1059
getname = 1;
1060
}
1061
stakputs(fake.nvname);
1062
stakputc('.');
1063
stakputs(event);
1064
stakputc(0);
1065
name = stakptr(off);
1066
mp = nv_search(name, shp->fun_tree, action?NV_ADD:0);
1067
stakseek(off);
1068
if(getname)
1069
return(mp?(char*)dtnext(shp->fun_tree,mp):0);
1070
if(action==np)
1071
action = mp;
1072
return(action?(char*)action:"");
1073
}
1074
1075
static const Namdisc_t SH_MATH_disc = { 0, 0, get_math, 0, setdisc_any, create_math, };
1076
1077
#if SHOPT_COSHELL
1078
static const Namdisc_t SH_JOBPOOL_disc = { 0, 0, 0, 0, setdisc_any, 0, };
1079
#endif /* SHOPT_COSHELL */
1080
1081
#if SHOPT_NAMESPACE
1082
static char* get_nspace(Namval_t* np, Namfun_t *fp)
1083
{
1084
if(sh.namespace)
1085
return(nv_name(sh.namespace));
1086
return((char*)np->nvalue.cp);
1087
}
1088
static const Namdisc_t NSPACE_disc = { 0, 0, get_nspace };
1089
static Namfun_t NSPACE_init = { &NSPACE_disc, 1};
1090
#endif /* SHOPT_NAMESPACE */
1091
1092
#ifdef _hdr_locale
1093
static const Namdisc_t LC_disc = { sizeof(Namfun_t), put_lang };
1094
#endif /* _hdr_locale */
1095
1096
/*
1097
* This function will get called whenever a configuration parameter changes
1098
*/
1099
static int newconf(const char *name, const char *path, const char *value)
1100
{
1101
Shell_t *shp = sh_getinterp();
1102
register char *arg;
1103
if(!name)
1104
setenviron(value);
1105
else if(strcmp(name,"UNIVERSE")==0 && strcmp(astconf(name,0,0),value))
1106
{
1107
shp->universe = 0;
1108
/* set directory in new universe */
1109
if(*(arg = path_pwd(shp,0))=='/')
1110
chdir(arg);
1111
/* clear out old tracked alias */
1112
stakseek(0);
1113
stakputs(nv_getval(PATHNOD));
1114
stakputc(0);
1115
nv_putval(PATHNOD,stakseek(0),NV_RDONLY);
1116
}
1117
return(1);
1118
}
1119
1120
#if (CC_NATIVE != CC_ASCII)
1121
static void a2e(char *d, const char *s)
1122
{
1123
register const unsigned char *t;
1124
register int i;
1125
t = CCMAP(CC_ASCII, CC_NATIVE);
1126
for(i=0; i<(1<<CHAR_BIT); i++)
1127
d[t[i]] = s[i];
1128
}
1129
1130
static void init_ebcdic(void)
1131
{
1132
int i;
1133
char *cp = (char*)malloc(ST_NONE*(1<<CHAR_BIT));
1134
for(i=0; i < ST_NONE; i++)
1135
{
1136
a2e(cp,sh_lexrstates[i]);
1137
sh_lexstates[i] = cp;
1138
cp += (1<<CHAR_BIT);
1139
}
1140
}
1141
#endif
1142
1143
/*
1144
* return SH_TYPE_* bitmask for path
1145
* 0 for "not a shell"
1146
*/
1147
int sh_type(register const char *path)
1148
{
1149
register const char* s;
1150
register int t = 0;
1151
1152
if (s = (const char*)strrchr(path, '/'))
1153
{
1154
if (*path == '-')
1155
t |= SH_TYPE_LOGIN;
1156
s++;
1157
}
1158
else
1159
s = path;
1160
if (*s == '-')
1161
{
1162
s++;
1163
t |= SH_TYPE_LOGIN;
1164
}
1165
for (;;)
1166
{
1167
if (!(t & (SH_TYPE_KSH|SH_TYPE_BASH)))
1168
{
1169
if (*s == 'k')
1170
{
1171
s++;
1172
t |= SH_TYPE_KSH;
1173
continue;
1174
}
1175
#if SHOPT_BASH
1176
if (*s == 'b' && *(s+1) == 'a')
1177
{
1178
s += 2;
1179
t |= SH_TYPE_BASH;
1180
continue;
1181
}
1182
#endif
1183
}
1184
if (!(t & (SH_TYPE_PROFILE|SH_TYPE_RESTRICTED)))
1185
{
1186
#if SHOPT_PFSH
1187
if (*s == 'p' && *(s+1) == 'f')
1188
{
1189
s += 2;
1190
t |= SH_TYPE_PROFILE;
1191
continue;
1192
}
1193
#endif
1194
if (*s == 'r')
1195
{
1196
s++;
1197
t |= SH_TYPE_RESTRICTED;
1198
continue;
1199
}
1200
}
1201
break;
1202
}
1203
if (*s++ == 's' && (*s == 'h' || *s == 'u'))
1204
{
1205
s++;
1206
t |= SH_TYPE_SH;
1207
if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3')
1208
s += 2;
1209
#if _WINIX
1210
if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e')
1211
s += 4;
1212
#endif
1213
if (!isalnum(*s))
1214
return t;
1215
}
1216
return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED);
1217
}
1218
1219
1220
static char *get_mode(Namval_t* np, Namfun_t* nfp)
1221
{
1222
mode_t mode = nv_getn(np,nfp);
1223
return(fmtperm(mode));
1224
}
1225
1226
static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1227
{
1228
if(val)
1229
{
1230
mode_t mode;
1231
char *last=0;
1232
if(flag&NV_INTEGER)
1233
{
1234
if(flag&NV_LONG)
1235
mode = *(Sfdouble_t*)val;
1236
else
1237
mode = *(double*)val;
1238
}
1239
else
1240
mode = strperm(val, &last,0);
1241
if(*last)
1242
errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val);
1243
nv_putv(np,(char*)&mode,NV_INTEGER,nfp);
1244
}
1245
else
1246
nv_putv(np,val,flag,nfp);
1247
}
1248
1249
static const Namdisc_t modedisc =
1250
{
1251
0,
1252
put_mode,
1253
get_mode,
1254
};
1255
1256
1257
/*
1258
* initialize the shell
1259
*/
1260
Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
1261
{
1262
static int beenhere;
1263
Shell_t *shp;
1264
register int n;
1265
int type;
1266
static char *login_files[3];
1267
memfatal();
1268
n = strlen(e_version);
1269
if(e_version[n-1]=='$' && e_version[n-2]==' ')
1270
e_version[n-2]=0;
1271
#if (CC_NATIVE == CC_ASCII)
1272
memcpy(sh_lexstates,sh_lexrstates,ST_NONE*sizeof(char*));
1273
#else
1274
init_ebcdic();
1275
#endif
1276
if(!beenhere)
1277
{
1278
beenhere = 1;
1279
shp = &sh;
1280
shgd = newof(0,struct shared,1,0);
1281
shgd->pid = getpid();
1282
shgd->ppid = getppid();
1283
shgd->userid=getuid();
1284
shgd->euserid=geteuid();
1285
shgd->groupid=getgid();
1286
shgd->egroupid=getegid();
1287
shgd->lim.clk_tck = getconf("CLK_TCK");
1288
shgd->lim.arg_max = getconf("ARG_MAX");
1289
shgd->lim.child_max = getconf("CHILD_MAX");
1290
shgd->lim.ngroups_max = getconf("NGROUPS_MAX");
1291
shgd->lim.posix_version = getconf("VERSION");
1292
shgd->lim.posix_jobcontrol = getconf("JOB_CONTROL");
1293
if(shgd->lim.arg_max <=0)
1294
shgd->lim.arg_max = ARG_MAX;
1295
if(shgd->lim.child_max <=0)
1296
shgd->lim.child_max = CHILD_MAX;
1297
if(shgd->lim.clk_tck <=0)
1298
shgd->lim.clk_tck = CLK_TCK;
1299
#if SHOPT_FS_3D
1300
if(fs3d(FS3D_TEST))
1301
shgd->lim.fs3d = 1;
1302
#endif /* SHOPT_FS_3D */
1303
shgd->ed_context = (void*)ed_open(shp);
1304
error_info.exit = sh_exit;
1305
error_info.id = path_basename(argv[0]);
1306
}
1307
else
1308
shp = newof(0,Shell_t,1,0);
1309
umask(shp->mask=umask(0));
1310
shp->gd = shgd;
1311
shp->mac_context = sh_macopen(shp);
1312
shp->arg_context = sh_argopen(shp);
1313
shp->lex_context = (void*)sh_lexopen(0,shp,1);
1314
shp->strbuf = sfstropen();
1315
shp->stk = stkstd;
1316
sfsetbuf(shp->strbuf,(char*)0,64);
1317
sh_onstate(SH_INIT);
1318
#if ERROR_VERSION >= 20000102L
1319
error_info.catalog = e_dict;
1320
#endif
1321
#if SHOPT_REGRESS
1322
{
1323
Opt_t* nopt;
1324
Opt_t* oopt;
1325
char* a;
1326
char** av = argv;
1327
char* regress[3];
1328
1329
sh_regress_init(shp);
1330
regress[0] = "__regress__";
1331
regress[2] = 0;
1332
/* NOTE: only shp is used by __regress__ at this point */
1333
shp->bltindata.shp = shp;
1334
while ((a = *++av) && a[0] == '-' && (a[1] == 'I' || a[1] == '-' && a[2] == 'r'))
1335
{
1336
if (a[1] == 'I')
1337
{
1338
if (a[2])
1339
regress[1] = a + 2;
1340
else if (!(regress[1] = *++av))
1341
break;
1342
}
1343
else if (strncmp(a+2, "regress", 7))
1344
break;
1345
else if (a[9] == '=')
1346
regress[1] = a + 10;
1347
else if (!(regress[1] = *++av))
1348
break;
1349
nopt = optctx(0, 0);
1350
oopt = optctx(nopt, 0);
1351
b___regress__(2, regress, &shp->bltindata);
1352
optctx(oopt, nopt);
1353
}
1354
}
1355
#endif
1356
shp->cpipe[0] = -1;
1357
shp->coutpipe = -1;
1358
for(n=0;n < 10; n++)
1359
{
1360
/* don't use lower bits when rand() generates large numbers */
1361
if(rand() > RANDMASK)
1362
{
1363
rand_shift = 3;
1364
break;
1365
}
1366
}
1367
sh_ioinit(shp);
1368
/* initialize signal handling */
1369
sh_siginit(shp);
1370
stakinstall(NIL(Stak_t*),nospace);
1371
/* set up memory for name-value pairs */
1372
shp->init_context = nv_init(shp);
1373
/* read the environment */
1374
if(argc>0)
1375
{
1376
type = sh_type(*argv);
1377
if(type&SH_TYPE_LOGIN)
1378
shp->login_sh = 2;
1379
}
1380
env_init(shp);
1381
if(!ENVNOD->nvalue.cp)
1382
{
1383
sfprintf(shp->strbuf,"%s/.kshrc",nv_getval(HOME));
1384
nv_putval(ENVNOD,sfstruse(shp->strbuf),NV_RDONLY);
1385
}
1386
*SHLVL->nvalue.ip +=1;
1387
nv_offattr(SHLVL,NV_IMPORT);
1388
#if SHOPT_SPAWN
1389
{
1390
/*
1391
* try to find the pathname for this interpreter
1392
* try using environment variable _ or argv[0]
1393
*/
1394
char *cp=nv_getval(L_ARGNOD);
1395
char buff[PATH_MAX+1];
1396
shp->gd->shpath = 0;
1397
#if _AST_VERSION >= 20090202L
1398
if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff))
1399
shp->gd->shpath = strdup(buff);
1400
#else
1401
sfprintf(shp->strbuf,"/proc/%d/exe",getpid());
1402
if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0)
1403
{
1404
buff[n] = 0;
1405
shp->gd->shpath = strdup(buff);
1406
}
1407
#endif
1408
else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
1409
{
1410
if(*cp=='/')
1411
shp->gd->shpath = strdup(cp);
1412
else if(cp = nv_getval(PWDNOD))
1413
{
1414
int offset = staktell();
1415
stakputs(cp);
1416
stakputc('/');
1417
stakputs(argv[0]);
1418
pathcanon(stakptr(offset),PATH_DOTDOT);
1419
shp->gd->shpath = strdup(stakptr(offset));
1420
stakseek(offset);
1421
}
1422
}
1423
}
1424
#endif
1425
nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
1426
#if SHOPT_FS_3D
1427
nv_stack(VPATHNOD, &VPATH_init);
1428
#endif /* SHOPT_FS_3D */
1429
astconfdisc(newconf);
1430
#if SHOPT_TIMEOUT
1431
shp->st.tmout = SHOPT_TIMEOUT;
1432
#endif /* SHOPT_TIMEOUT */
1433
/* initialize jobs table */
1434
job_clear();
1435
sh_onoption(SH_MULTILINE);
1436
if(argc>0)
1437
{
1438
/* check for restricted shell */
1439
if(type&SH_TYPE_RESTRICTED)
1440
sh_onoption(SH_RESTRICTED);
1441
#if SHOPT_PFSH
1442
/* check for profile shell */
1443
else if(type&SH_TYPE_PROFILE)
1444
sh_onoption(SH_PFSH);
1445
#endif
1446
#if SHOPT_BASH
1447
/* check for invocation as bash */
1448
if(type&SH_TYPE_BASH)
1449
{
1450
shp>userinit = userinit = bash_init;
1451
sh_onoption(SH_BASH);
1452
sh_onstate(SH_PREINIT);
1453
(*userinit)(shp, 0);
1454
sh_offstate(SH_PREINIT);
1455
}
1456
#endif
1457
/* look for options */
1458
/* shp->st.dolc is $# */
1459
if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0)
1460
{
1461
shp->exitval = 2;
1462
sh_done(shp,0);
1463
}
1464
opt_info.disc = 0;
1465
shp->st.dolv=argv+(argc-1)-shp->st.dolc;
1466
shp->st.dolv[0] = argv[0];
1467
if(shp->st.dolc < 1)
1468
sh_onoption(SH_SFLAG);
1469
if(!sh_isoption(SH_SFLAG))
1470
{
1471
shp->st.dolc--;
1472
shp->st.dolv++;
1473
#if _WINIX
1474
{
1475
char* name;
1476
name = shp->st.dolv[0];
1477
if(name[1]==':' && (name[2]=='/' || name[2]=='\\'))
1478
{
1479
#if _lib_pathposix
1480
char* p;
1481
1482
if((n = pathposix(name, NIL(char*), 0)) > 0 && (p = (char*)malloc(++n)))
1483
{
1484
pathposix(name, p, n);
1485
name = p;
1486
}
1487
else
1488
#endif
1489
{
1490
name[1] = name[0];
1491
name[0] = name[2] = '/';
1492
}
1493
}
1494
}
1495
#endif /* _WINIX */
1496
}
1497
if(beenhere==1)
1498
{
1499
struct lconv* lc;
1500
shp->decomma = (lc=localeconv()) && lc->decimal_point && *lc->decimal_point==',';
1501
beenhere = 2;
1502
}
1503
}
1504
#if SHOPT_PFSH
1505
if (sh_isoption(SH_PFSH))
1506
{
1507
struct passwd *pw = getpwuid(shp->gd->userid);
1508
if(pw)
1509
shp->gd->user = strdup(pw->pw_name);
1510
1511
}
1512
#endif
1513
/* set[ug]id scripts require the -p flag */
1514
if(shp->gd->userid!=shp->gd->euserid || shp->gd->groupid!=shp->gd->egroupid)
1515
{
1516
#ifdef SHOPT_P_SUID
1517
/* require sh -p to run setuid and/or setgid */
1518
if(!sh_isoption(SH_PRIVILEGED) && shp->gd->userid >= SHOPT_P_SUID)
1519
{
1520
setuid(shp->gd->euserid=shp->gd->userid);
1521
setgid(shp->gd->egroupid=shp->gd->groupid);
1522
}
1523
else
1524
#endif /* SHOPT_P_SUID */
1525
sh_onoption(SH_PRIVILEGED);
1526
#ifdef SHELLMAGIC
1527
/* careful of #! setuid scripts with name beginning with - */
1528
if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0)
1529
errormsg(SH_DICT,ERROR_exit(1),e_prohibited);
1530
#endif /*SHELLMAGIC*/
1531
}
1532
else
1533
sh_offoption(SH_PRIVILEGED);
1534
/* shname for $0 in profiles and . scripts */
1535
if(sh_isdevfd(argv[1]))
1536
shp->shname = strdup(argv[0]);
1537
else
1538
shp->shname = strdup(shp->st.dolv[0]);
1539
/*
1540
* return here for shell script execution
1541
* but not for parenthesis subshells
1542
*/
1543
error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */
1544
shp->jmpbuffer = (void*)&shp->checkbase;
1545
sh_pushcontext(shp,&shp->checkbase,SH_JMPSCRIPT);
1546
shp->st.self = &shp->global;
1547
shp->topscope = (Shscope_t*)shp->st.self;
1548
sh_offstate(SH_INIT);
1549
login_files[0] = (char*)e_profile;
1550
login_files[1] = ".profile";
1551
shp->gd->login_files = login_files;
1552
shp->bltindata.version = SH_VERSION;
1553
shp->bltindata.shp = shp;
1554
shp->bltindata.shrun = sh_run;
1555
shp->bltindata.shtrap = sh_trap;
1556
shp->bltindata.shexit = sh_exit;
1557
shp->bltindata.shbltin = sh_addbuiltin;
1558
#if _AST_VERSION >= 20080617L
1559
shp->bltindata.shgetenv = sh_getenv;
1560
shp->bltindata.shsetenv = sh_setenviron;
1561
astintercept(&shp->bltindata,1);
1562
#endif
1563
#if 0
1564
#define NV_MKINTTYPE(x,y,z) nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z);
1565
NV_MKINTTYPE(pid_t,"process id",0);
1566
NV_MKINTTYPE(gid_t,"group id",0);
1567
NV_MKINTTYPE(uid_t,"user id",0);
1568
NV_MKINTTYPE(size_t,(const char*)0,0);
1569
NV_MKINTTYPE(ssize_t,(const char*)0,0);
1570
NV_MKINTTYPE(off_t,"offset in bytes",0);
1571
NV_MKINTTYPE(ino_t,"\ai-\anode number",0);
1572
NV_MKINTTYPE(mode_t,(const char*)0,&modedisc);
1573
NV_MKINTTYPE(dev_t,"device id",0);
1574
NV_MKINTTYPE(nlink_t,"hard link count",0);
1575
NV_MKINTTYPE(blkcnt_t,"block count",0);
1576
NV_MKINTTYPE(time_t,"seconds since the epoch",0);
1577
nv_mkstat();
1578
#endif
1579
if(shp->userinit=userinit)
1580
(*userinit)(shp, 0);
1581
return(shp);
1582
}
1583
1584
Shell_t *sh_getinterp(void)
1585
{
1586
return(&sh);
1587
}
1588
1589
/*
1590
* reinitialize before executing a script
1591
*/
1592
int sh_reinit(char *argv[])
1593
{
1594
Shell_t *shp = sh_getinterp();
1595
Shopt_t opt;
1596
Namval_t *np,*npnext;
1597
Dt_t *dp;
1598
struct adata
1599
{
1600
Shell_t *sh;
1601
void *extra[2];
1602
} data;
1603
for(np=dtfirst(shp->fun_tree);np;np=npnext)
1604
{
1605
if((dp=shp->fun_tree)->walk)
1606
dp = dp->walk;
1607
npnext = (Namval_t*)dtnext(shp->fun_tree,np);
1608
if(np>= shgd->bltin_cmds && np < &shgd->bltin_cmds[nbltins])
1609
continue;
1610
if(is_abuiltin(np) && nv_isattr(np,NV_EXPORT))
1611
continue;
1612
if(*np->nvname=='/')
1613
continue;
1614
nv_delete(np,dp,NV_NOFREE);
1615
}
1616
dtclose(shp->alias_tree);
1617
shp->alias_tree = inittree(shp,shtab_aliases);
1618
shp->last_root = shp->var_tree;
1619
shp->inuse_bits = 0;
1620
if(shp->userinit)
1621
(*shp->userinit)(shp, 1);
1622
if(shp->heredocs)
1623
{
1624
sfclose(shp->heredocs);
1625
shp->heredocs = 0;
1626
}
1627
/* remove locals */
1628
sh_onstate(SH_INIT);
1629
memset(&data,0,sizeof(data));
1630
data.sh = shp;
1631
nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_EXPORT,0);
1632
nv_scan(shp->var_tree,sh_envnolocal,(void*)&data,NV_ARRAY,NV_ARRAY);
1633
sh_offstate(SH_INIT);
1634
memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*));
1635
memset((void*)&opt,0,sizeof(opt));
1636
#if SHOPT_NAMESPACE
1637
if(shp->namespace)
1638
{
1639
dp=nv_dict(shp->namespace);
1640
if(dp==shp->var_tree)
1641
shp->var_tree = dtview(dp,0);
1642
_nv_unset(shp->namespace,NV_RDONLY);
1643
shp->namespace = 0;
1644
}
1645
#endif /* SHOPT_NAMESPACE */
1646
if(sh_isoption(SH_TRACKALL))
1647
on_option(&opt,SH_TRACKALL);
1648
if(sh_isoption(SH_EMACS))
1649
on_option(&opt,SH_EMACS);
1650
if(sh_isoption(SH_GMACS))
1651
on_option(&opt,SH_GMACS);
1652
if(sh_isoption(SH_VI))
1653
on_option(&opt,SH_VI);
1654
if(sh_isoption(SH_VIRAW))
1655
on_option(&opt,SH_VIRAW);
1656
shp->options = opt;
1657
/* set up new args */
1658
if(argv)
1659
shp->arglist = sh_argcreate(argv);
1660
if(shp->arglist)
1661
sh_argreset(shp,shp->arglist,NIL(struct dolnod*));
1662
shp->envlist=0;
1663
shp->curenv = 0;
1664
shp->shname = error_info.id = strdup(shp->st.dolv[0]);
1665
sh_offstate(SH_FORKED);
1666
shp->fn_depth = shp->dot_depth = 0;
1667
sh_sigreset(0);
1668
if(!(SHLVL->nvalue.ip))
1669
{
1670
shlvl = 0;
1671
SHLVL->nvalue.ip = &shlvl;
1672
nv_onattr(SHLVL,NV_INTEGER|NV_EXPORT|NV_NOFREE);
1673
}
1674
*SHLVL->nvalue.ip +=1;
1675
nv_offattr(SHLVL,NV_IMPORT);
1676
shp->st.filename = strdup(shp->lastarg);
1677
nv_delete((Namval_t*)0, (Dt_t*)0, 0);
1678
job.exitval = 0;
1679
shp->inpipe = shp->outpipe = 0;
1680
job_clear();
1681
job.in_critical = 0;
1682
return(1);
1683
}
1684
1685
/*
1686
* set when creating a local variable of this name
1687
*/
1688
Namfun_t *nv_cover(register Namval_t *np)
1689
{
1690
if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS || np==ENVNOD || np==LINENO)
1691
return(np->nvfun);
1692
#ifdef _hdr_locale
1693
if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD)
1694
return(np->nvfun);
1695
#endif
1696
return(0);
1697
}
1698
1699
static const char *shdiscnames[] = { "tilde", 0};
1700
1701
#ifdef SHOPT_STATS
1702
struct Stats
1703
{
1704
Namfun_t hdr;
1705
Shell_t *sh;
1706
char *nodes;
1707
int numnodes;
1708
int current;
1709
};
1710
1711
static Namval_t *next_stat(register Namval_t* np, Dt_t *root,Namfun_t *fp)
1712
{
1713
struct Stats *sp = (struct Stats*)fp;
1714
if(!root)
1715
sp->current = 0;
1716
else if(++sp->current>=sp->numnodes)
1717
return(0);
1718
return(nv_namptr(sp->nodes,sp->current));
1719
}
1720
1721
static Namval_t *create_stat(Namval_t *np,const char *name,int flag,Namfun_t *fp)
1722
{
1723
struct Stats *sp = (struct Stats*)fp;
1724
register const char *cp=name;
1725
register int i=0,n;
1726
Namval_t *nq=0;
1727
Shell_t *shp = sp->sh;
1728
if(!name)
1729
return(SH_STATS);
1730
while((i=*cp++) && i != '=' && i != '+' && i!='[');
1731
n = (cp-1) -name;
1732
for(i=0; i < sp->numnodes; i++)
1733
{
1734
nq = nv_namptr(sp->nodes,i);
1735
if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0)
1736
goto found;
1737
}
1738
nq = 0;
1739
found:
1740
if(nq)
1741
{
1742
fp->last = (char*)&name[n];
1743
shp->last_table = SH_STATS;
1744
}
1745
else
1746
errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np));
1747
return(nq);
1748
}
1749
1750
static const Namdisc_t stat_disc =
1751
{
1752
0, 0, 0, 0, 0,
1753
create_stat,
1754
0, 0,
1755
next_stat
1756
};
1757
1758
static char *name_stat(Namval_t *np, Namfun_t *fp)
1759
{
1760
Shell_t *shp = sh_getinterp();
1761
sfprintf(shp->strbuf,".sh.stats.%s",np->nvname);
1762
return(sfstruse(shp->strbuf));
1763
}
1764
1765
static const Namdisc_t stat_child_disc =
1766
{
1767
0,0,0,0,0,0,0,
1768
name_stat
1769
};
1770
1771
static Namfun_t stat_child_fun =
1772
{
1773
&stat_child_disc, 1, 0, sizeof(Namfun_t)
1774
};
1775
1776
static void stat_init(Shell_t *shp)
1777
{
1778
int i,nstat = STAT_SUBSHELL+1;
1779
struct Stats *sp = newof(0,struct Stats,1,nstat*NV_MINSZ);
1780
Namval_t *np;
1781
sp->numnodes = nstat;
1782
sp->nodes = (char*)(sp+1);
1783
shgd->stats = (int*)calloc(sizeof(int),nstat);
1784
sp->sh = shp;
1785
for(i=0; i < nstat; i++)
1786
{
1787
np = nv_namptr(sp->nodes,i);
1788
np->nvfun = &stat_child_fun;
1789
np->nvname = (char*)shtab_stats[i].sh_name;
1790
nv_onattr(np,NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER);
1791
nv_setsize(np,10);
1792
np->nvalue.ip = &shgd->stats[i];
1793
}
1794
sp->hdr.dsize = sizeof(struct Stats) + nstat*(sizeof(int)+NV_MINSZ);
1795
sp->hdr.disc = &stat_disc;
1796
nv_stack(SH_STATS,&sp->hdr);
1797
sp->hdr.nofree = 1;
1798
nv_setvtree(SH_STATS);
1799
}
1800
#else
1801
# define stat_init(x)
1802
#endif /* SHOPT_STATS */
1803
1804
/*
1805
* Initialize the shell name and alias table
1806
*/
1807
static Init_t *nv_init(Shell_t *shp)
1808
{
1809
double d=0;
1810
ip = newof(0,Init_t,1,0);
1811
if(!ip)
1812
return(0);
1813
shp->nvfun.last = (char*)shp;
1814
shp->nvfun.nofree = 1;
1815
ip->sh = shp;
1816
shp->var_base = shp->var_tree = inittree(shp,shtab_variables);
1817
SHLVL->nvalue.ip = &shlvl;
1818
ip->IFS_init.hdr.disc = &IFS_disc;
1819
ip->PATH_init.disc = &RESTRICTED_disc;
1820
ip->PATH_init.nofree = 1;
1821
ip->FPATH_init.disc = &RESTRICTED_disc;
1822
ip->FPATH_init.nofree = 1;
1823
ip->CDPATH_init.disc = &CDPATH_disc;
1824
ip->CDPATH_init.nofree = 1;
1825
ip->SHELL_init.disc = &RESTRICTED_disc;
1826
ip->SHELL_init.nofree = 1;
1827
ip->ENV_init.disc = &RESTRICTED_disc;
1828
ip->ENV_init.nofree = 1;
1829
ip->VISUAL_init.disc = &EDITOR_disc;
1830
ip->VISUAL_init.nofree = 1;
1831
ip->EDITOR_init.disc = &EDITOR_disc;
1832
ip->EDITOR_init.nofree = 1;
1833
ip->HISTFILE_init.disc = &HISTFILE_disc;
1834
ip->HISTFILE_init.nofree = 1;
1835
ip->HISTSIZE_init.disc = &HISTFILE_disc;
1836
ip->HISTSIZE_init.nofree = 1;
1837
ip->OPTINDEX_init.disc = &OPTINDEX_disc;
1838
ip->OPTINDEX_init.nofree = 1;
1839
ip->SECONDS_init.hdr.disc = &SECONDS_disc;
1840
ip->SECONDS_init.hdr.nofree = 1;
1841
ip->RAND_init.hdr.disc = &RAND_disc;
1842
ip->RAND_init.hdr.nofree = 1;
1843
ip->RAND_init.sh = shp;
1844
ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc;
1845
ip->SH_MATCH_init.hdr.nofree = 1;
1846
ip->SH_MATH_init.disc = &SH_MATH_disc;
1847
ip->SH_MATH_init.nofree = 1;
1848
#if SHOPT_COSHELL
1849
ip->SH_JOBPOOL_init.disc = &SH_JOBPOOL_disc;
1850
ip->SH_JOBPOOL_init.nofree = 1;
1851
nv_stack(SH_JOBPOOL, &ip->SH_JOBPOOL_init);
1852
#endif /* SHOPT_COSHELL */
1853
ip->SH_VERSION_init.disc = &SH_VERSION_disc;
1854
ip->SH_VERSION_init.nofree = 1;
1855
ip->LINENO_init.disc = &LINENO_disc;
1856
ip->LINENO_init.nofree = 1;
1857
ip->L_ARG_init.disc = &L_ARG_disc;
1858
ip->L_ARG_init.nofree = 1;
1859
#ifdef _hdr_locale
1860
ip->LC_TYPE_init.disc = &LC_disc;
1861
ip->LC_TYPE_init.nofree = 1;
1862
ip->LC_NUM_init.disc = &LC_disc;
1863
ip->LC_NUM_init.nofree = 1;
1864
ip->LC_COLL_init.disc = &LC_disc;
1865
ip->LC_COLL_init.nofree = 1;
1866
ip->LC_MSG_init.disc = &LC_disc;
1867
ip->LC_MSG_init.nofree = 1;
1868
ip->LC_ALL_init.disc = &LC_disc;
1869
ip->LC_ALL_init.nofree = 1;
1870
ip->LANG_init.disc = &LC_disc;
1871
ip->LANG_init.nofree = 1;
1872
#endif /* _hdr_locale */
1873
nv_stack(IFSNOD, &ip->IFS_init.hdr);
1874
ip->IFS_init.hdr.nofree = 1;
1875
nv_stack(PATHNOD, &ip->PATH_init);
1876
nv_stack(FPATHNOD, &ip->FPATH_init);
1877
nv_stack(CDPNOD, &ip->CDPATH_init);
1878
nv_stack(SHELLNOD, &ip->SHELL_init);
1879
nv_stack(ENVNOD, &ip->ENV_init);
1880
nv_stack(VISINOD, &ip->VISUAL_init);
1881
nv_stack(EDITNOD, &ip->EDITOR_init);
1882
nv_stack(HISTFILE, &ip->HISTFILE_init);
1883
nv_stack(HISTSIZE, &ip->HISTSIZE_init);
1884
nv_stack(OPTINDNOD, &ip->OPTINDEX_init);
1885
nv_stack(SECONDS, &ip->SECONDS_init.hdr);
1886
nv_stack(L_ARGNOD, &ip->L_ARG_init);
1887
nv_putval(SECONDS, (char*)&d, NV_DOUBLE);
1888
nv_stack(RANDNOD, &ip->RAND_init.hdr);
1889
d = (shp->gd->pid&RANDMASK);
1890
nv_putval(RANDNOD, (char*)&d, NV_DOUBLE);
1891
nv_stack(LINENO, &ip->LINENO_init);
1892
SH_MATCHNOD->nvfun = &ip->SH_MATCH_init.hdr;
1893
nv_putsub(SH_MATCHNOD,(char*)0,10);
1894
nv_stack(SH_MATHNOD, &ip->SH_MATH_init);
1895
nv_stack(SH_VERSIONNOD, &ip->SH_VERSION_init);
1896
#ifdef _hdr_locale
1897
nv_stack(LCTYPENOD, &ip->LC_TYPE_init);
1898
nv_stack(LCALLNOD, &ip->LC_ALL_init);
1899
nv_stack(LCMSGNOD, &ip->LC_MSG_init);
1900
nv_stack(LCCOLLNOD, &ip->LC_COLL_init);
1901
nv_stack(LCNUMNOD, &ip->LC_NUM_init);
1902
nv_stack(LANGNOD, &ip->LANG_init);
1903
#endif /* _hdr_locale */
1904
(PPIDNOD)->nvalue.lp = (&shp->gd->ppid);
1905
(TMOUTNOD)->nvalue.lp = (&shp->st.tmout);
1906
(MCHKNOD)->nvalue.lp = (&sh_mailchk);
1907
(OPTINDNOD)->nvalue.lp = (&shp->st.optindex);
1908
/* set up the seconds clock */
1909
shp->alias_tree = inittree(shp,shtab_aliases);
1910
shp->track_tree = dtopen(&_Nvdisc,Dtset);
1911
shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins);
1912
shp->fun_tree = dtopen(&_Nvdisc,Dtoset);
1913
dtview(shp->fun_tree,shp->bltin_tree);
1914
nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset));
1915
nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0);
1916
DOTSHNOD->nvalue.cp = Empty;
1917
nv_onattr(DOTSHNOD,NV_RDONLY);
1918
SH_LINENO->nvalue.ip = &shp->st.lineno;
1919
VERSIONNOD->nvalue.nrp = newof(0,struct Namref,1,0);
1920
VERSIONNOD->nvalue.nrp->np = SH_VERSIONNOD;
1921
VERSIONNOD->nvalue.nrp->root = nv_dict(DOTSHNOD);
1922
VERSIONNOD->nvalue.nrp->table = DOTSHNOD;
1923
nv_onattr(VERSIONNOD,NV_REF);
1924
math_init(shp);
1925
if(!shgd->stats)
1926
stat_init(shp);
1927
return(ip);
1928
}
1929
1930
/*
1931
* initialize name-value pairs
1932
*/
1933
1934
static Dt_t *inittree(Shell_t *shp,const struct shtable2 *name_vals)
1935
{
1936
register Namval_t *np;
1937
register const struct shtable2 *tp;
1938
register unsigned n = 0;
1939
register Dt_t *treep;
1940
Dt_t *base_treep, *dict;
1941
for(tp=name_vals;*tp->sh_name;tp++)
1942
n++;
1943
np = (Namval_t*)calloc(n,sizeof(Namval_t));
1944
if(!shgd->bltin_nodes)
1945
{
1946
shgd->bltin_nodes = np;
1947
shgd->bltin_nnodes = n;
1948
}
1949
else if(name_vals==(const struct shtable2*)shtab_builtins)
1950
{
1951
shgd->bltin_cmds = np;
1952
nbltins = n;
1953
}
1954
base_treep = treep = dtopen(&_Nvdisc,Dtoset);
1955
treep->user = (void*)shp;
1956
for(tp=name_vals;*tp->sh_name;tp++,np++)
1957
{
1958
if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name))
1959
np->nvname++;
1960
else
1961
{
1962
np->nvname = (char*)tp->sh_name;
1963
treep = base_treep;
1964
}
1965
np->nvenv = 0;
1966
if(name_vals==(const struct shtable2*)shtab_builtins)
1967
np->nvalue.bfp = (Nambfp_f)((struct shtable3*)tp)->sh_value;
1968
else
1969
{
1970
if(name_vals == shtab_variables)
1971
np->nvfun = &shp->nvfun;
1972
np->nvalue.cp = (char*)tp->sh_value;
1973
}
1974
nv_setattr(np,tp->sh_number);
1975
if(nv_isattr(np,NV_TABLE))
1976
nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset));
1977
if(nv_isattr(np,NV_INTEGER))
1978
nv_setsize(np,10);
1979
else
1980
nv_setsize(np,0);
1981
dtinsert(treep,np);
1982
if(nv_istable(np))
1983
treep = dict;
1984
}
1985
return(treep);
1986
}
1987
1988
/*
1989
* read in the process environment and set up name-value pairs
1990
* skip over items that are not name-value pairs
1991
*/
1992
1993
static void env_init(Shell_t *shp)
1994
{
1995
register char *cp;
1996
register Namval_t *np,*mp;
1997
register char **ep=environ;
1998
char *dp,*next=0;
1999
int nenv=0,k=0,size=0;
2000
Namval_t *np0;
2001
#ifdef _ENV_H
2002
shp->env = env_open(environ,3);
2003
env_delete(shp->env,"_");
2004
#endif
2005
if(!ep)
2006
goto skip;
2007
while(*ep++)
2008
nenv++;
2009
np = newof(0,Namval_t,nenv,0);
2010
for(np0=np,ep=environ;cp= *ep; ep++)
2011
{
2012
dp = strchr(cp,'=');
2013
if(!dp)
2014
continue;
2015
*dp++ = 0;
2016
if(mp = dtmatch(shp->var_base,cp))
2017
{
2018
mp->nvenv = (char*)cp;
2019
dp[-1] = '=';
2020
}
2021
else if(*cp=='A' && cp[1]=='_' && cp[2]=='_' && cp[3]=='z' && cp[4]==0)
2022
{
2023
dp[-1] = '=';
2024
next = cp+4;
2025
continue;
2026
}
2027
else
2028
{
2029
k++;
2030
mp = np++;
2031
mp->nvname = cp;
2032
size += strlen(cp);
2033
}
2034
nv_onattr(mp,NV_IMPORT);
2035
if(mp->nvfun || nv_isattr(mp,NV_INTEGER))
2036
nv_putval(mp,dp,0);
2037
else
2038
{
2039
mp->nvalue.cp = dp;
2040
nv_onattr(mp,NV_NOFREE);
2041
}
2042
nv_onattr(mp,NV_EXPORT|NV_IMPORT);
2043
}
2044
np = (Namval_t*)realloc((void*)np0,k*sizeof(Namval_t));
2045
dp = (char*)malloc(size+k);
2046
while(k-->0)
2047
{
2048
size = strlen(np->nvname);
2049
memcpy(dp,np->nvname,size+1);
2050
np->nvname[size] = '=';
2051
np->nvenv = np->nvname;
2052
np->nvname = dp;
2053
dp += size+1;
2054
dtinsert(shp->var_base,np++);
2055
}
2056
while(cp=next)
2057
{
2058
if(next = strchr(++cp,'='))
2059
*next = 0;
2060
np = nv_search(cp+2,shp->var_tree,NV_ADD);
2061
if(np!=SHLVL && nv_isattr(np,NV_IMPORT|NV_EXPORT))
2062
{
2063
int flag = *(unsigned char*)cp-' ';
2064
int size = *(unsigned char*)(cp+1)-' ';
2065
if((flag&NV_INTEGER) && size==0)
2066
{
2067
/* check for floating*/
2068
char *val = nv_getval(np);
2069
strtol(val,&dp,10);
2070
if(*dp=='.' || *dp=='e' || *dp=='E')
2071
{
2072
char *lp;
2073
flag |= NV_DOUBLE;
2074
if(*dp=='.')
2075
{
2076
strtol(dp+1,&lp,10);
2077
if(*lp)
2078
dp = lp;
2079
}
2080
if(*dp && *dp!='.')
2081
{
2082
flag |= NV_EXPNOTE;
2083
size = dp-val;
2084
}
2085
else
2086
size = strlen(dp);
2087
size--;
2088
}
2089
}
2090
nv_newattr(np,flag|NV_IMPORT|NV_EXPORT,size);
2091
if((flag&(NV_INTEGER|NV_UTOL|NV_LTOU))==(NV_UTOL|NV_LTOU))
2092
nv_mapchar(np,(flag&NV_UTOL)?e_tolower:e_toupper);
2093
}
2094
else
2095
cp += 2;
2096
}
2097
skip:
2098
#ifdef _ENV_H
2099
env_delete(shp->env,e_envmarker);
2100
#endif
2101
if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED))
2102
{
2103
nv_offattr(PWDNOD,NV_TAGGED);
2104
path_pwd(shp,0);
2105
}
2106
if((cp = nv_getval(SHELLNOD)) && (sh_type(cp)&SH_TYPE_RESTRICTED))
2107
sh_onoption(SH_RESTRICTED); /* restricted shell */
2108
return;
2109
}
2110
2111
/*
2112
* terminate shell and free up the space
2113
*/
2114
int sh_term(void)
2115
{
2116
sfdisc(sfstdin,SF_POPDISC);
2117
free((char*)sh.outbuff);
2118
stakset(NIL(char*),0);
2119
return(0);
2120
}
2121
2122
/* function versions of these */
2123
2124
#define DISABLE /* proto workaround */
2125
2126
unsigned long sh_isoption DISABLE (int opt)
2127
{
2128
return(sh_isoption(opt));
2129
}
2130
2131
unsigned long sh_onoption DISABLE (int opt)
2132
{
2133
return(sh_onoption(opt));
2134
}
2135
2136
unsigned long sh_offoption DISABLE (int opt)
2137
{
2138
return(sh_offoption(opt));
2139
}
2140
2141
void sh_sigcheck DISABLE (Shell_t *shp)
2142
{
2143
if(!shp)
2144
shp = sh_getinterp();
2145
sh_sigcheck(shp);
2146
}
2147
2148
Dt_t* sh_bltin_tree DISABLE (void)
2149
{
2150
return(sh.bltin_tree);
2151
}
2152
2153
/*
2154
* This code is for character mapped variables with wctrans()
2155
*/
2156
struct Mapchar
2157
{
2158
Namfun_t hdr;
2159
const char *name;
2160
wctrans_t trans;
2161
int lctype;
2162
};
2163
2164
static void put_trans(register Namval_t* np,const char *val,int flags,Namfun_t *fp)
2165
{
2166
struct Mapchar *mp = (struct Mapchar*)fp;
2167
int c,offset = staktell(),off=offset;
2168
if(val)
2169
{
2170
if(mp->lctype!=lctype)
2171
{
2172
mp->lctype = lctype;
2173
mp->trans = wctrans(mp->name);
2174
}
2175
if(!mp->trans || (flags&NV_INTEGER))
2176
goto skip;
2177
while(c = mbchar(val))
2178
{
2179
c = towctrans(c,mp->trans);
2180
stakseek(off+c);
2181
stakseek(off);
2182
c = mbconv(stakptr(off),c);
2183
off += c;
2184
stakseek(off);
2185
}
2186
stakputc(0);
2187
val = stakptr(offset);
2188
}
2189
else
2190
{
2191
nv_putv(np,val,flags,fp);
2192
nv_disc(np,fp,NV_POP);
2193
if(!(fp->nofree&1))
2194
free((void*)fp);
2195
stakseek(offset);
2196
return;
2197
}
2198
skip:
2199
nv_putv(np,val,flags,fp);
2200
stakseek(offset);
2201
}
2202
2203
static const Namdisc_t TRANS_disc = { sizeof(struct Mapchar), put_trans };
2204
2205
Namfun_t *nv_mapchar(Namval_t *np,const char *name)
2206
{
2207
wctrans_t trans = name?wctrans(name):0;
2208
struct Mapchar *mp=0;
2209
int n=0,low;
2210
if(np)
2211
mp = (struct Mapchar*)nv_hasdisc(np,&TRANS_disc);
2212
if(!name)
2213
return(mp?(Namfun_t*)mp->name:0);
2214
if(!trans)
2215
return(0);
2216
if(!np)
2217
return(((Namfun_t*)0)+1);
2218
if((low=strcmp(name,e_tolower)) && strcmp(name,e_toupper))
2219
n += strlen(name)+1;
2220
if(mp)
2221
{
2222
if(strcmp(name,mp->name)==0)
2223
return(&mp->hdr);
2224
nv_disc(np,&mp->hdr,NV_POP);
2225
if(!(mp->hdr.nofree&1))
2226
free((void*)mp);
2227
}
2228
mp = newof(0,struct Mapchar,1,n);
2229
mp->trans = trans;
2230
mp->lctype = lctype;
2231
if(low==0)
2232
mp->name = e_tolower;
2233
else if(n==0)
2234
mp->name = e_toupper;
2235
else
2236
{
2237
mp->name = (char*)(mp+1);
2238
strcpy((char*)mp->name,name);
2239
}
2240
mp->hdr.disc = &TRANS_disc;
2241
return(&mp->hdr);
2242
}
2243
2244