Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/args.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
* UNIX shell
23
*
24
* S. R. Bourne
25
* Rewritten by David Korn
26
* AT&T Labs
27
*
28
*/
29
30
#include "defs.h"
31
#include "path.h"
32
#include "builtins.h"
33
#include "terminal.h"
34
#include "edit.h"
35
#include "FEATURE/poll"
36
#if SHOPT_KIA
37
# include "shlex.h"
38
# include "io.h"
39
#endif /* SHOPT_KIA */
40
#if SHOPT_PFSH
41
# define PFSHOPT "P"
42
#else
43
# define PFSHOPT
44
#endif
45
#if SHOPT_BASH
46
# define BASHOPT "\374"
47
#else
48
# define BASHOPT
49
#endif
50
#if SHOPT_HISTEXPAND
51
# define HFLAG "H"
52
#else
53
# define HFLAG ""
54
#endif
55
56
#define SORT 1
57
#define PRINT 2
58
59
static char *null;
60
61
/* The following order is determined by sh_optset */
62
static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG;
63
static const int flagval[] =
64
{
65
#if SHOPT_PFSH
66
SH_PFSH,
67
#endif
68
#if SHOPT_BASH
69
SH_POSIX,
70
#endif
71
SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG,
72
SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL,
73
SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG,
74
SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER,
75
SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL,
76
#if SHOPT_HISTEXPAND
77
SH_HISTEXPAND,
78
#endif
79
0
80
};
81
82
#define NUM_OPTS (sizeof(flagval)/sizeof(*flagval))
83
84
typedef struct _arg_
85
{
86
Shell_t *sh;
87
struct dolnod *argfor; /* linked list of blocks to be cleaned up */
88
struct dolnod *dolh;
89
char flagadr[NUM_OPTS+1];
90
#if SHOPT_KIA
91
char *kiafile;
92
#endif /* SHOPT_KIA */
93
} Arg_t;
94
95
static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int);
96
static void sh_argset(Arg_t*, char *[]);
97
98
99
/* ======== option handling ======== */
100
101
void *sh_argopen(Shell_t *shp)
102
{
103
void *addr = newof(0,Arg_t,1,0);
104
Arg_t *ap = (Arg_t*)addr;
105
ap->sh = shp;
106
return(addr);
107
}
108
109
static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
110
{
111
#if SHOPT_BASH
112
extern const char sh_bash1[], sh_bash2[];
113
if(strcmp(s,"bash1")==0)
114
{
115
if(sh_isoption(SH_BASH))
116
sfputr(sp,sh_bash1,-1);
117
}
118
else if(strcmp(s,"bash2")==0)
119
{
120
if(sh_isoption(SH_BASH))
121
sfputr(sp,sh_bash2,-1);
122
}
123
else if(*s==':' && sh_isoption(SH_BASH))
124
sfputr(sp,s,-1);
125
else
126
#endif
127
if(*s!=':')
128
sfputr(sp,sh_set,-1);
129
return(1);
130
}
131
132
/*
133
* This routine turns options on and off
134
* The options "PDicr" are illegal from set command.
135
* The -o option is used to set option by name
136
* This routine returns the number of non-option arguments
137
*/
138
int sh_argopts(int argc,register char *argv[], void *context)
139
{
140
Shell_t *shp = (Shell_t*)context;
141
register int n,o;
142
register Arg_t *ap = (Arg_t*)(shp->arg_context);
143
Lex_t *lp = (Lex_t*)(shp->lex_context);
144
Shopt_t newflags;
145
int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE);
146
Namval_t *np = NIL(Namval_t*);
147
const char *cp;
148
int verbose,f;
149
Optdisc_t disc;
150
newflags=ap->sh->options;
151
memset(&disc, 0, sizeof(disc));
152
disc.version = OPT_VERSION;
153
disc.infof = infof;
154
opt_info.disc = &disc;
155
156
if(argc>0)
157
setflag = 4;
158
else
159
argc = -argc;
160
while((n = optget(argv,setflag?sh_optset:sh_optksh)))
161
{
162
o=0;
163
f=*opt_info.option=='-' && (opt_info.num || opt_info.arg);
164
switch(n)
165
{
166
case 'A':
167
np = nv_open(opt_info.arg,ap->sh->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME);
168
if(f)
169
nv_unset(np);
170
continue;
171
#if SHOPT_BASH
172
case 'O': /* shopt options, only in bash mode */
173
if(!sh_isoption(SH_BASH))
174
errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name);
175
#endif
176
case 'o': /* set options */
177
byname:
178
if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-')
179
{
180
action = PRINT;
181
/* print style: -O => shopt options
182
* bash => print unset options also, no heading
183
*/
184
verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)|
185
(n=='O'?PRINT_SHOPT:0)|
186
(sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)|
187
((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0);
188
continue;
189
}
190
o = sh_lookopt(opt_info.arg,&f);
191
if(o<=0
192
|| (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA))
193
|| ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT))
194
195
|| (setflag && (o&SH_COMMANDLINE)))
196
{
197
errormsg(SH_DICT,2, e_option, opt_info.arg);
198
error_info.errors++;
199
}
200
o &= 0xff;
201
if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED)
202
errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg);
203
break;
204
#if SHOPT_BASH
205
case -1: /* --rcfile */
206
ap->sh->gd->rcfile = opt_info.arg;
207
continue;
208
case -2: /* --noediting */
209
if (!f)
210
{
211
off_option(&newflags,SH_VI);
212
off_option(&newflags,SH_EMACS);
213
off_option(&newflags,SH_GMACS);
214
}
215
continue;
216
case -3: /* --profile */
217
n = 'l';
218
goto skip;
219
case -4: /* --posix */
220
/* mask lower 8 bits to find char in optksh string */
221
n&=0xff;
222
goto skip;
223
case -5: /* --version */
224
sfputr(sfstdout, "ksh bash emulation, version ",-1);
225
np = nv_open("BASH_VERSION",ap->sh->var_tree,0);
226
sfputr(sfstdout, nv_getval(np),-1);
227
np = nv_open("MACHTYPE",ap->sh->var_tree,0);
228
sfprintf(sfstdout, " (%s)\n", nv_getval(np));
229
sh_exit(0);
230
#endif
231
case -6: /* --default */
232
{
233
register const Shtable_t *tp;
234
for(tp=shtab_options; o = tp->sh_number; tp++)
235
if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff))
236
off_option(&newflags,o&0xff);
237
}
238
continue;
239
case -7:
240
f = 0;
241
goto byname;
242
case 'D':
243
on_option(&newflags,SH_NOEXEC);
244
goto skip;
245
case 'T':
246
if (opt_info.num)
247
ap->sh->test |= opt_info.num;
248
else
249
ap->sh->test = 0;
250
continue;
251
case 's':
252
if(setflag)
253
{
254
action = SORT;
255
continue;
256
}
257
#if SHOPT_KIA
258
goto skip;
259
case 'R':
260
if(setflag)
261
n = ':';
262
else
263
{
264
ap->kiafile = opt_info.arg;
265
n = 'n';
266
}
267
/*FALLTHROUGH*/
268
#endif /* SHOPT_KIA */
269
#if SHOPT_REGRESS
270
goto skip;
271
case 'I':
272
continue;
273
#endif /* SHOPT_REGRESS */
274
skip:
275
default:
276
if(cp=strchr(optksh,n))
277
o = flagval[cp-optksh];
278
break;
279
case ':':
280
if(opt_info.name[0]=='-'&&opt_info.name[1]=='-')
281
{
282
opt_info.arg = argv[opt_info.index-1] + 2;
283
f = 1;
284
goto byname;
285
}
286
errormsg(SH_DICT,2, "%s", opt_info.arg);
287
continue;
288
case '?':
289
errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
290
return(-1);
291
}
292
if(f)
293
{
294
if(o==SH_VI || o==SH_EMACS || o==SH_GMACS)
295
{
296
off_option(&newflags,SH_VI);
297
off_option(&newflags,SH_EMACS);
298
off_option(&newflags,SH_GMACS);
299
}
300
on_option(&newflags,o);
301
off_option(&ap->sh->offoptions,o);
302
}
303
else
304
{
305
if(o==SH_XTRACE)
306
trace = 0;
307
off_option(&newflags,o);
308
if(setflag==0)
309
on_option(&ap->sh->offoptions,o);
310
}
311
}
312
if(error_info.errors)
313
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
314
/* check for '-' or '+' argument */
315
if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') &&
316
strcmp(argv[opt_info.index-1],"--"))
317
{
318
opt_info.index++;
319
off_option(&newflags,SH_XTRACE);
320
off_option(&newflags,SH_VERBOSE);
321
trace = 0;
322
}
323
if(trace)
324
sh_trace(shp,argv,1);
325
argc -= opt_info.index;
326
argv += opt_info.index;
327
if(action==PRINT)
328
sh_printopts(newflags,verbose,0);
329
if(setflag)
330
{
331
if(action==SORT)
332
{
333
if(argc>0)
334
strsort(argv,argc,strcoll);
335
else
336
strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll);
337
}
338
if(np)
339
{
340
nv_setvec(np,0,argc,argv);
341
nv_close(np);
342
}
343
else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0))
344
sh_argset(ap,argv-1);
345
}
346
else if(is_option(&newflags,SH_CFLAG))
347
{
348
if(!(ap->sh->comdiv = *argv++))
349
{
350
errormsg(SH_DICT,2,e_cneedsarg);
351
errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
352
}
353
argc--;
354
}
355
/* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to
356
* sh_applyopts(), so that the code can be reused from b_shopt(), too
357
*/
358
sh_applyopts(ap->sh,newflags);
359
#if SHOPT_KIA
360
if(ap->kiafile)
361
{
362
if(!argv[0])
363
errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname");
364
if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+")))
365
errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile);
366
if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE)))
367
errormsg(SH_DICT,ERROR_system(3),e_tmpcreate);
368
sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n');
369
lp->kiabegin = sftell(lp->kiafile);
370
lp->entity_tree = dtopen(&_Nvdisc,Dtbag);
371
lp->scriptname = strdup(sh_fmtq(argv[0]));
372
lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,"");
373
lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,"");
374
lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,"");
375
kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,"");
376
lp->current = lp->script;
377
ap->kiafile = 0;
378
}
379
#endif /* SHOPT_KIA */
380
return(argc);
381
}
382
383
/* apply new options */
384
385
void sh_applyopts(Shell_t* shp,Shopt_t newflags)
386
{
387
/* cannot set -n for interactive shells since there is no way out */
388
if(sh_isoption(SH_INTERACTIVE))
389
off_option(&newflags,SH_NOEXEC);
390
if(is_option(&newflags,SH_PRIVILEGED))
391
on_option(&newflags,SH_NOUSRPROFILE);
392
if(!sh_isstate(SH_INIT) && is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED) || sh_isstate(SH_INIT) && is_option(&((Arg_t*)shp->arg_context)->sh->offoptions,SH_PRIVILEGED) && shp->gd->userid!=shp->gd->euserid)
393
{
394
if(!is_option(&newflags,SH_PRIVILEGED))
395
{
396
setuid(shp->gd->userid);
397
setgid(shp->gd->groupid);
398
if(shp->gd->euserid==0)
399
{
400
shp->gd->euserid = shp->gd->userid;
401
shp->gd->egroupid = shp->gd->groupid;
402
}
403
}
404
else if((shp->gd->userid!=shp->gd->euserid && setuid(shp->gd->euserid)<0) ||
405
(shp->gd->groupid!=shp->gd->egroupid && setgid(shp->gd->egroupid)<0) ||
406
(shp->gd->userid==shp->gd->euserid && shp->gd->groupid==shp->gd->egroupid))
407
off_option(&newflags,SH_PRIVILEGED);
408
}
409
#if SHOPT_BASH
410
on_option(&newflags,SH_CMDHIST);
411
on_option(&newflags,SH_CHECKHASH);
412
on_option(&newflags,SH_EXECFAIL);
413
on_option(&newflags,SH_EXPAND_ALIASES);
414
on_option(&newflags,SH_HISTAPPEND);
415
on_option(&newflags,SH_INTERACTIVE_COMM);
416
on_option(&newflags,SH_LITHIST);
417
on_option(&newflags,SH_NOEMPTYCMDCOMPL);
418
419
if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO))
420
astconf("UNIVERSE", 0, "ucb");
421
if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO))
422
astconf("UNIVERSE", 0, "att");
423
if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL))
424
astconf("PATH_RESOLVE", 0, "metaphysical");
425
if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL))
426
astconf("PATH_RESOLVE", 0, "physical");
427
if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2))
428
{
429
sh_onstate(SH_HISTORY);
430
sh_onoption(SH_HISTORY);
431
}
432
if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2))
433
{
434
sh_offstate(SH_HISTORY);
435
sh_offoption(SH_HISTORY);
436
}
437
#endif
438
shp->options = newflags;
439
}
440
441
/*
442
* returns the value of $-
443
*/
444
char *sh_argdolminus(void* context)
445
{
446
register Arg_t *ap = (Arg_t*)context;
447
register const char *cp=optksh;
448
register char *flagp=ap->flagadr;
449
while(cp< &optksh[NUM_OPTS])
450
{
451
int n = flagval[cp-optksh];
452
if(sh_isoption(n))
453
*flagp++ = *cp;
454
cp++;
455
}
456
*flagp = 0;
457
return(ap->flagadr);
458
}
459
460
/*
461
* set up positional parameters
462
*/
463
static void sh_argset(Arg_t *ap,char *argv[])
464
{
465
sh_argfree(ap->sh,ap->dolh,0);
466
ap->dolh = sh_argcreate(argv);
467
/* link into chain */
468
ap->dolh->dolnxt = ap->argfor;
469
ap->argfor = ap->dolh;
470
ap->sh->st.dolc = ap->dolh->dolnum-1;
471
ap->sh->st.dolv = ap->dolh->dolval;
472
}
473
474
/*
475
* free the argument list if the use count is 1
476
* If count is greater than 1 decrement count and return same blk
477
* Free the argument list if the use count is 1 and return next blk
478
* Delete the blk from the argfor chain
479
* If flag is set, then the block dolh is not freed
480
*/
481
struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag)
482
{
483
register struct dolnod* argr=blk;
484
register struct dolnod* argblk;
485
register Arg_t *ap = (Arg_t*)shp->arg_context;
486
if(argblk=argr)
487
{
488
if((--argblk->dolrefcnt)==0)
489
{
490
argr = argblk->dolnxt;
491
if(flag && argblk==ap->dolh)
492
ap->dolh->dolrefcnt = 1;
493
else
494
{
495
/* delete from chain */
496
if(ap->argfor == argblk)
497
ap->argfor = argblk->dolnxt;
498
else
499
{
500
for(argr=ap->argfor;argr;argr=argr->dolnxt)
501
if(argr->dolnxt==argblk)
502
break;
503
if(!argr)
504
return(NIL(struct dolnod*));
505
argr->dolnxt = argblk->dolnxt;
506
argr = argblk->dolnxt;
507
}
508
free((void*)argblk);
509
}
510
}
511
}
512
return(argr);
513
}
514
515
/*
516
* grab space for arglist and copy args
517
* The strings are copied after the argment vector
518
*/
519
struct dolnod *sh_argcreate(register char *argv[])
520
{
521
register struct dolnod *dp;
522
register char **pp=argv, *sp;
523
register int size=0,n;
524
/* count args and number of bytes of arglist */
525
while(sp= *pp++)
526
size += strlen(sp);
527
n = (pp - argv)-1;
528
dp=new_of(struct dolnod,n*sizeof(char*)+size+n);
529
dp->dolrefcnt=1; /* use count */
530
dp->dolnum = n;
531
dp->dolnxt = 0;
532
pp = dp->dolval;
533
sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*);
534
while(n--)
535
{
536
*pp++ = sp;
537
sp = strcopy(sp, *argv++) + 1;
538
}
539
*pp = NIL(char*);
540
return(dp);
541
}
542
543
/*
544
* used to set new arguments for functions
545
*/
546
struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor)
547
{
548
register Arg_t *ap = (Arg_t*)shp->arg_context;
549
register struct dolnod *olddolh = ap->dolh;
550
*savargfor = ap->argfor;
551
ap->dolh = 0;
552
ap->argfor = 0;
553
sh_argset(ap,argi);
554
return(olddolh);
555
}
556
557
/*
558
* reset arguments as they were before function
559
*/
560
void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor)
561
{
562
register Arg_t *ap = (Arg_t*)shp->arg_context;
563
while(ap->argfor=sh_argfree(shp,ap->argfor,0));
564
ap->argfor = afor;
565
if(ap->dolh = blk)
566
{
567
shp->st.dolc = ap->dolh->dolnum-1;
568
shp->st.dolv = ap->dolh->dolval;
569
}
570
}
571
572
/*
573
* increase the use count so that an sh_argset will not make it go away
574
*/
575
struct dolnod *sh_arguse(Shell_t* shp)
576
{
577
register struct dolnod *dh;
578
register Arg_t *ap = (Arg_t*)shp->arg_context;
579
if(dh=ap->dolh)
580
dh->dolrefcnt++;
581
return(dh);
582
}
583
584
/*
585
* Print option settings on standard output
586
* if mode is inclusive or of PRINT_*
587
* if <mask> is set, only options with this mask value are displayed
588
*/
589
void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask)
590
{
591
register const Shtable_t *tp;
592
const char *name;
593
int on;
594
int value;
595
if(!(mode&PRINT_NO_HEADER))
596
sfputr(sfstdout,sh_translate(e_heading),'\n');
597
if(mode&PRINT_TABLE)
598
{
599
int w;
600
int c;
601
int r;
602
int i;
603
604
c = 0;
605
for(tp=shtab_options; value=tp->sh_number; tp++)
606
{
607
if(mask && !is_option(mask,value&0xff))
608
continue;
609
name = tp->sh_name;
610
if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
611
name += 2;
612
if(c<(w=strlen(name)))
613
c = w;
614
}
615
c += 4;
616
if((w = ed_window()) < (2*c))
617
w = 2*c;
618
r = w / c;
619
i = 0;
620
for(tp=shtab_options; value=tp->sh_number; tp++)
621
{
622
if(mask && !is_option(mask,value&0xff))
623
continue;
624
on = !!is_option(&oflags,value);
625
value &= 0xff;
626
name = tp->sh_name;
627
if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
628
{
629
name += 2;
630
on = !on;
631
}
632
if(++i>=r)
633
{
634
i = 0;
635
sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name);
636
}
637
else
638
sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name);
639
}
640
if(i)
641
sfputc(sfstdout,'\n');
642
return;
643
}
644
#if SHOPT_RAWONLY
645
on_option(&oflags,SH_VIRAW);
646
#endif
647
if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */
648
{
649
if(mode&PRINT_SHOPT)
650
sfwrite(sfstdout,"shopt -s",3);
651
else
652
sfwrite(sfstdout,"set --default",13);
653
}
654
for(tp=shtab_options; value=tp->sh_number; tp++)
655
{
656
if(mask && !is_option(mask,value&0xff))
657
continue;
658
if(sh_isoption(SH_BASH))
659
{
660
if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT))
661
continue;
662
}
663
else if (value&(SH_BASHEXTRA|SH_BASHOPT))
664
continue;
665
on = !!is_option(&oflags,value);
666
name = tp->sh_name;
667
if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
668
{
669
name += 2;
670
on = !on;
671
}
672
if(mode&PRINT_VERBOSE)
673
{
674
sfputr(sfstdout,name,' ');
675
sfnputc(sfstdout,' ',24-strlen(name));
676
sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n');
677
}
678
else if(mode&PRINT_ALL) /* print unset options also */
679
{
680
if(mode&PRINT_SHOPT)
681
sfprintf(sfstdout, "shopt -%c %s\n",
682
on?'s':'u',
683
name);
684
else
685
sfprintf(sfstdout, "set %co %s\n",
686
on?'-':'+',
687
name);
688
}
689
else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff))
690
sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name);
691
}
692
if(!(mode&(PRINT_VERBOSE|PRINT_ALL)))
693
sfputc(sfstdout,'\n');
694
}
695
696
/*
697
* build an argument list
698
*/
699
char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag)
700
{
701
register struct argnod *argp;
702
struct argnod *arghead=0;
703
shp->xargmin = 0;
704
{
705
register const struct comnod *ac = comptr;
706
register int n;
707
/* see if the arguments have already been expanded */
708
if(!ac->comarg)
709
{
710
*nargs = 0;
711
return(&null);
712
}
713
else if(!(ac->comtyp&COMSCAN))
714
{
715
register struct dolnod *ap = (struct dolnod*)ac->comarg;
716
*nargs = ap->dolnum;
717
return(ap->dolval+ap->dolbot);
718
}
719
shp->lastpath = 0;
720
*nargs = 0;
721
if(ac)
722
{
723
if(ac->comnamp == SYSLET)
724
flag |= ARG_LET;
725
argp = ac->comarg;
726
while(argp)
727
{
728
n = arg_expand(shp,argp,&arghead,flag);
729
if(n>1)
730
{
731
if(shp->xargmin==0)
732
shp->xargmin = *nargs;
733
shp->xargmax = *nargs+n;
734
}
735
*nargs += n;
736
argp = argp->argnxt.ap;
737
}
738
argp = arghead;
739
}
740
}
741
{
742
register char **comargn;
743
register int argn;
744
register char **comargm;
745
argn = *nargs;
746
/* allow room to prepend args */
747
argn += 1;
748
749
comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*));
750
comargm = comargn += argn;
751
*comargn = NIL(char*);
752
if(!argp)
753
{
754
/* reserve an extra null pointer */
755
*--comargn = 0;
756
return(comargn);
757
}
758
while(argp)
759
{
760
struct argnod *nextarg = argp->argchn.ap;
761
argp->argchn.ap = 0;
762
*--comargn = argp->argval;
763
if(!(argp->argflag&ARG_RAW))
764
sh_trim(*comargn);
765
if(!(argp=nextarg) || (argp->argflag&ARG_MAKE))
766
{
767
if((argn=comargm-comargn)>1)
768
strsort(comargn,argn,strcoll);
769
comargm = comargn;
770
}
771
}
772
shp->last_table = 0;
773
return(comargn);
774
}
775
}
776
777
#if _pipe_socketpair && !_socketpair_devfd
778
# define sh_pipe(a) sh_rpipe(a)
779
#endif
780
781
struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
782
{
783
/* argument of the form <(cmd) or >(cmd) */
784
register struct argnod *ap;
785
int monitor, fd, pv[3];
786
int subshell = shp->subshell;
787
ap = (struct argnod*)stkseek(shp->stk,ARGVAL);
788
ap->argflag |= ARG_MAKE;
789
ap->argflag &= ~ARG_RAW;
790
fd = argp->argflag&ARG_RAW;
791
if(fd==0 && shp->subshell)
792
sh_subtmpfile(shp);
793
#if SHOPT_DEVFD
794
sfwrite(shp->stk,e_devfdNN,8);
795
pv[2] = 0;
796
sh_pipe(pv);
797
#else
798
pv[0] = -1;
799
shp->fifo = pathtemp(0,0,0,"ksh.fifo",0);
800
mkfifo(shp->fifo,S_IRUSR|S_IWUSR);
801
sfputr(shp->stk,shp->fifo,0);
802
#endif /* SHOPT_DEVFD */
803
sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0);
804
ap = (struct argnod*)stkfreeze(shp->stk,0);
805
shp->inpipe = shp->outpipe = 0;
806
if(monitor = (sh_isstate(SH_MONITOR)!=0))
807
sh_offstate(SH_MONITOR);
808
shp->subshell = 0;
809
if(fd)
810
{
811
shp->inpipe = pv;
812
sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
813
}
814
else
815
{
816
shp->outpipe = pv;
817
sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
818
}
819
shp->subshell = subshell;
820
if(monitor)
821
sh_onstate(SH_MONITOR);
822
#if SHOPT_DEVFD
823
close(pv[1-fd]);
824
sh_iosave(shp,-pv[fd], shp->topfd, (char*)0);
825
#else
826
free(shp->fifo);
827
shp->fifo = 0;
828
#endif /* SHOPT_DEVFD */
829
return(ap);
830
}
831
832
/* Argument expansion */
833
static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag)
834
{
835
register int count = 0;
836
argp->argflag &= ~ARG_MAKE;
837
if(*argp->argval==0 && (argp->argflag&ARG_EXP))
838
{
839
struct argnod *ap;
840
ap = sh_argprocsub(shp,argp);
841
ap->argchn.ap = *argchain;
842
*argchain = ap;
843
count++;
844
}
845
else
846
if(!(argp->argflag&ARG_RAW))
847
{
848
#if SHOPT_OPTIMIZE
849
struct argnod *ap;
850
sh_stats(STAT_ARGEXPAND);
851
if(flag&ARG_OPTIMIZE)
852
argp->argchn.ap=0;
853
if(ap=argp->argchn.ap)
854
{
855
sh_stats(STAT_ARGHITS);
856
count = 1;
857
ap->argchn.ap = *argchain;
858
ap->argflag |= ARG_RAW;
859
ap->argflag &= ~ARG_EXP;
860
*argchain = ap;
861
}
862
else
863
#endif /* SHOPT_OPTIMIZE */
864
count = sh_macexpand(shp,argp,argchain,flag);
865
}
866
else
867
{
868
argp->argchn.ap = *argchain;
869
*argchain = argp;
870
argp->argflag |= ARG_MAKE;
871
count++;
872
}
873
return(count);
874
}
875
876
877