1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
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
sh_argopen(Shell_t * shp)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
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)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 */
sh_argopts(int argc,register char * argv[],void * context)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->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(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
sh_applyopts(Shell_t * shp,Shopt_t newflags)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->userid!=shp->euserid)
393 {
394 if(!is_option(&newflags,SH_PRIVILEGED))
395 {
396 setuid(shp->userid);
397 setgid(shp->groupid);
398 if(shp->euserid==0)
399 {
400 shp->euserid = shp->userid;
401 shp->egroupid = shp->groupid;
402 }
403 }
404 else if((shp->userid!=shp->euserid && setuid(shp->euserid)<0) ||
405 (shp->groupid!=shp->egroupid && setgid(shp->egroupid)<0) ||
406 (shp->userid==shp->euserid && shp->groupid==shp->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 */
sh_argdolminus(void * context)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 */
sh_argset(Arg_t * ap,char * argv[])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 */
sh_argfree(Shell_t * shp,struct dolnod * blk,int flag)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 */
sh_argcreate(register char * argv[])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 */
sh_argnew(Shell_t * shp,char * argi[],struct dolnod ** savargfor)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 */
sh_argreset(Shell_t * shp,struct dolnod * blk,struct dolnod * afor)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 */
sh_arguse(Shell_t * shp)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 */
sh_printopts(Shopt_t oflags,register int mode,Shopt_t * mask)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 */
sh_argbuild(Shell_t * shp,int * nargs,const struct comnod * comptr,int flag)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 arg_pipe
779 /*
780 * create a real pipe (not a socket) and print message on failure
781 */
arg_pipe(register int pv[])782 static int arg_pipe(register int pv[])
783 {
784 int fd[2];
785 if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
786 errormsg(SH_DICT,ERROR_system(1),e_pipe);
787 pv[0] = sh_iomovefd(pv[0]);
788 pv[1] = sh_iomovefd(pv[1]);
789 sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
790 sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
791 sh_subsavefd(pv[0]);
792 sh_subsavefd(pv[1]);
793 return(0);
794 }
795 #endif
796
sh_argprocsub(Shell_t * shp,struct argnod * argp)797 struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
798 {
799 /* argument of the form <(cmd) or >(cmd) */
800 register struct argnod *ap;
801 int monitor, fd, pv[2];
802 int subshell = shp->subshell;
803 ap = (struct argnod*)stkseek(shp->stk,ARGVAL);
804 ap->argflag |= ARG_MAKE;
805 ap->argflag &= ~ARG_RAW;
806 sfwrite(shp->stk,e_devfdNN,8);
807 sh_pipe(pv);
808 fd = argp->argflag&ARG_RAW;
809 sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0);
810 ap = (struct argnod*)stkfreeze(shp->stk,0);
811 shp->inpipe = shp->outpipe = 0;
812 if(monitor = (sh_isstate(SH_MONITOR)!=0))
813 sh_offstate(SH_MONITOR);
814 shp->subshell = 0;
815 if(fd)
816 {
817 shp->inpipe = pv;
818 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
819 }
820 else
821 {
822 shp->outpipe = pv;
823 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
824 }
825 shp->subshell = subshell;
826 if(monitor)
827 sh_onstate(SH_MONITOR);
828 close(pv[1-fd]);
829 sh_iosave(shp,-pv[fd], shp->topfd, (char*)0);
830 return(ap);
831 }
832
833 /* Argument expansion */
arg_expand(Shell_t * shp,register struct argnod * argp,struct argnod ** argchain,int flag)834 static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag)
835 {
836 register int count = 0;
837 argp->argflag &= ~ARG_MAKE;
838 #if SHOPT_DEVFD
839 if(*argp->argval==0 && (argp->argflag&ARG_EXP))
840 {
841 struct argnod *ap;
842 ap = sh_argprocsub(shp,argp);
843 ap->argchn.ap = *argchain;
844 *argchain = ap;
845 count++;
846 }
847 else
848 #endif /* SHOPT_DEVFD */
849 if(!(argp->argflag&ARG_RAW))
850 {
851 #if SHOPT_OPTIMIZE
852 struct argnod *ap;
853 sh_stats(STAT_ARGEXPAND);
854 if(flag&ARG_OPTIMIZE)
855 argp->argchn.ap=0;
856 if(ap=argp->argchn.ap)
857 {
858 sh_stats(STAT_ARGHITS);
859 count = 1;
860 ap->argchn.ap = *argchain;
861 ap->argflag |= ARG_RAW;
862 ap->argflag &= ~ARG_EXP;
863 *argchain = ap;
864 }
865 else
866 #endif /* SHOPT_OPTIMIZE */
867 count = sh_macexpand(shp,argp,argchain,flag);
868 }
869 else
870 {
871 argp->argchn.ap = *argchain;
872 *argchain = argp;
873 argp->argflag |= ARG_MAKE;
874 count++;
875 }
876 return(count);
877 }
878
879