1 /*
2
3 * Copyright (c) 1984, 1985, 1986 AT&T
4 * All Rights Reserved
5
6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE
7 * CODE OF AT&T.
8 * The copyright notice above does not
9 * evidence any actual or intended
10 * publication of such source code.
11
12 */
13 /* @(#)args.c 1.1 */
14 /*
15 * UNIX shell
16 *
17 * S. R. Bourne
18 * Rewritten by David Korn
19 * AT&T Bell Laboratories
20 *
21 */
22
23 #include "flags.h"
24 #include "defs.h"
25 #include "sym.h"
26 #include "mode.h"
27 #include "name.h"
28 #include "io.h"
29 #include "builtins.h"
30 #include "brkincr.h"
31 #include "stak.h"
32 #ifdef DEVFD
33 # ifdef JOBS
34 #include "jobs.h"
35 # endif /* JOBS */
36 #endif /* DEVFD */
37
38
39 void arg_set();
40 void arg_reset();
41 void arg_clear();
42 DOLPTR arg_free();
43 DOLPTR arg_use();
44 DOLPTR arg_new();
45 int arg_opts();
46 char **arg_build();
47 char *arg_dolminus();
48 #ifdef DEVFD
49 void close_pipes();
50 #endif /* DEVFD */
51
52 extern char *malloc();
53 extern char *macro();
54 extern char *movstr();
55 extern char *strchr();
56 extern char *itos();
57 extern void assign();
58 extern void failed();
59 extern void chkpipe();
60 extern void exitsh();
61 extern void free();
62 extern void gsort();
63 extern void trim();
64 extern void p_str();
65 extern void p_nchr();
66 extern void p_setout();
67 extern char *qvalup();
68
69 static int arg_expand();
70 static DOLPTR copyargs();
71 static void print_opts();
72 static int split();
73
74 static char *null;
75 static DOLPTR argfor; /* linked list of blocks to be cleaned up */
76 static DOLPTR dolh;
77 static char flagadr[12];
78 static const char flagchar[] =
79 {
80 'i', 'n', 'v', 't', 's', 'x', 'e', 'r', 'k',
81 'u', 'f', 'a', 'm', 'h', 'p', 'c', 0
82 };
83 static const optflag flagval[] =
84 {
85 INTFLG, NOEXEC, READPR, ONEFLG, STDFLG, EXECPR, ERRFLG, RSHFLG, KEYFLG,
86 NOSET, NOGLOB, ALLEXP, MONITOR, HASHALL, PRIVM, CFLAG, 0
87 };
88
89 /* ======== option handling ======== */
90
91 /*
92 * This routine turns options on and off
93 * The options "sicr" are illegal from set command.
94 * The -o option is used to set option by name
95 * This routine returns the number of non-option arguments
96 */
97
arg_opts(argc,argv)98 int arg_opts(argc,argv)
99 char **argv;
100 int argc;
101 {
102 register char *cp;
103 register int c;
104 register char **argp=argv;
105 register char *flagc;
106 register optflag newflags=flags;
107 register optflag opt;
108 char minus;
109 int sort = 0;
110 int setflag = eq(*argp,bset);
111 while((cp= *++argp) && ((c= *cp) == '-' || c=='+'))
112 {
113 minus = (c == '-');
114 argc--;
115 if((c= *++cp)==0)
116 {
117 newflags &= ~(EXECPR|READPR);
118 argp++;
119 break;
120 }
121 else if(c == '-')
122 {
123 if(setflag)
124 states |= RWAIT;
125 argp++;
126 break;
127 }
128 while(c= *cp++)
129 {
130 if(setflag)
131 {
132 if(c=='s')
133 {
134 sort++;
135 continue;
136 }
137 else if(strchr("icr",c))
138 failed(argv[1], badopt);
139 }
140 if(c=='c' && minus && argc>=2 && comdiv==0)
141 {
142 comdiv= *++argp;
143 argc--;
144 newflags |= CFLAG;
145 continue;
146 }
147 if(flagc=strchr(flagchar,c))
148 opt = flagval[flagc-flagchar];
149 else if(c != 'o')
150 failed(argv[1],badopt);
151 else
152 {
153 argp++;
154 if(*argp==NULL)
155 {
156 print_opts(newflags);
157 argp--;
158 continue;
159 }
160 else
161 {
162 argc--;
163 c=syslook(*argp,option_flags);
164 opt = 1L<<c;
165 if(opt&(1|INTFLG|RSHFLG))
166 failed(*argp,badopt);
167 }
168 }
169 if(minus)
170 {
171 #if ESH || VSH
172 if(opt&(EDITVI|EMACS|GMACS))
173 newflags &= ~ (EDITVI|EMACS|GMACS);
174 #endif
175 newflags |= opt;
176 }
177 else
178 newflags &= ~opt;
179 }
180 }
181 /* cannot set -n for interactive shells since there is no way out */
182 if(is_option(INTFLG))
183 newflags &= ~NOEXEC;
184 #ifdef RAWONLY
185 if(is_option(EDITVI))
186 newflags |= VIRAW;
187 #endif /* RAWONLY */
188 if(sort)
189 {
190 if(argc>1)
191 gsort(argp,argc-1);
192 else
193 gsort(dolv+1,dolc);
194 }
195 if((newflags&PRIVM) && !is_option(PRIVM))
196 assign(PATHNOD,defpath);
197 flags = newflags;
198 return(argc);
199 }
200
201 /*
202 * returns the value of $-
203 */
204
arg_dolminus()205 char *arg_dolminus()
206 {
207 register char *flagc=flagchar;
208 register char *flagp=flagadr;
209 while(*flagc)
210 {
211 if(flags&flagval[flagc-flagchar])
212 *flagp++ = *flagc;
213 flagc++;
214 }
215 *flagp++=0;
216 return(flagadr);
217 }
218
219 /*
220 * set up positional parameters
221 */
222
arg_set(argi)223 void arg_set(argi)
224 char *argi[];
225 {
226 register char **argp=argi;
227 register int size = 0; /* count number of bytes needed for strings */
228 register int argn=0;
229 register char *cp;
230 /* count args and number of bytes of arglist */
231 while((cp=(char*)*argp++) != ENDARGS)
232 {
233 size += strlen(cp);
234 }
235 /* free old ones unless on for loop chain */
236 argn = argp - argi;
237 arg_free(dolh,0);
238 dolh=copyargs(argi, --argn, size);
239 dolc=argn-1;
240 }
241
242 /*
243 * free the argument list if the use count is 1
244 * If count is greater than 1 decrement count and return same blk
245 * Free the argument list if the use count is 1 and return next blk
246 * Delete the blk from the argfor chain
247 * If flag is set, then the block dolh is not freed
248 */
249
arg_free(blk,flag)250 DOLPTR arg_free(blk,flag)
251 DOLPTR blk;
252 {
253 register DOLPTR argr=blk;
254 register DOLPTR argblk;
255 if(argblk=argr)
256 {
257 if((--argblk->doluse)==0)
258 {
259 if(flag && argblk==dolh)
260 dolh->doluse = 1;
261 else
262 {
263 /* delete from chain */
264 if(argfor == argblk)
265 argfor = argblk->dolnxt;
266 else
267 {
268 for(argr=argfor;argr;argr=argr->dolnxt)
269 if(argr->dolnxt==argblk)
270 break;
271 if(argr==0)
272 {
273 return(NULL);
274 }
275 argr->dolnxt = argblk->dolnxt;
276 }
277 free((char*)argblk);
278 }
279 argr = argblk->dolnxt;
280 }
281 }
282 return(argr);
283 }
284
285 /*
286 * grab space for arglist and link argblock for cleanup
287 * The strings are copied after the argment vector
288 */
289
copyargs(from,n,size)290 static DOLPTR copyargs(from, n, size)
291 char *from[];
292 {
293 register DOLPTR dp=(DOLPTR)malloc((unsigned)(DOLTYPE + n*sizeof(char*) + size + n));
294 register char **pp;
295 register char *sp;
296 dp->doluse=1; /* use count */
297 /* link into chain */
298 dp->dolnxt = argfor;
299 argfor = dp;
300 pp= dp->dolarg;
301 dolv=pp;
302 sp = (char*)dp + DOLTYPE + n*sizeof(char*);
303 while(n--)
304 {
305 *pp++ = sp;
306 sp = movstr(*from++,sp) + 1;
307 }
308 *pp = ENDARGS;
309 return(dp);
310 }
311
312 /*
313 * used to set new argument chain for functions
314 */
315
arg_new(argi,savargfor)316 DOLPTR arg_new(argi,savargfor)
317 char *argi[];
318 DOLPTR *savargfor;
319 {
320 register DOLPTR olddolh = dolh;
321 *savargfor = argfor;
322 dolh = NULL;
323 argfor = NULL;
324 arg_set(argi);
325 return(olddolh);
326 }
327
328 /*
329 * reset arguments as they were before function
330 */
331
arg_reset(blk,afor)332 void arg_reset(blk,afor)
333 DOLPTR blk;
334 DOLPTR afor;
335 {
336 while(argfor=arg_free(argfor,0));
337 dolh = blk;
338 argfor = afor;
339 }
340
arg_clear()341 void arg_clear()
342 {
343 /* force `for' $* lists to go away */
344 while(argfor=arg_free(argfor,1));
345 /* clean up io files */
346 argfor = dolh;
347 while(pop(0));
348 #ifdef DEVFD
349 close_pipes();
350 #endif /* DEVFD */
351 }
352
353 /*
354 * increase the use count so that an arg_set will not make it go away
355 */
356
arg_use()357 DOLPTR arg_use()
358 {
359 register DOLPTR dh;
360 if(dh=dolh)
361 dh->doluse++;
362 return(dh);
363 }
364
365 /*
366 * Print option settings on standard output
367 */
368
print_opts(oflags)369 static void print_opts(oflags)
370 #ifndef pdp11
371 register
372 #endif /* pdp11 */
373 optflag oflags;
374 {
375 register SYSPTR syscan = option_flags;
376 #ifndef pdp11
377 register
378 #endif /* pdp11 */
379 optflag value;
380 p_setout(standout);
381 p_str(opt_heading,NL);
382 while(value=syscan->sysval)
383 {
384 value = 1<<value;
385 p_str(syscan->sysnam,SP);
386 p_nchr(SP,16-strlen(syscan->sysnam));
387 if(oflags&value)
388 p_str(on_,NL);
389 else
390 p_str(off_,NL);
391 syscan++;
392 }
393 }
394
395
396 /*
397 * build an argument list
398 */
399
arg_build(nargs,comptr)400 char **arg_build(nargs,comptr)
401 int *nargs;
402 COMPTR comptr;
403 {
404 register ARGPTR argp;
405 {
406 register COMPTR ac = comptr;
407 register ARGPTR schain;
408 /* see if the arguments have already been expanded */
409 if(ac->comarg==NULL)
410 {
411 *nargs = 0;
412 return(&null);
413 }
414 else if((ac->comtyp&COMSCAN)==0)
415 {
416 *nargs = ((DOLPTR)ac->comarg)->doluse;
417 return(((DOLPTR)ac->comarg)->dolarg+1);
418 }
419 schain = gchain;
420 gchain = NULL;
421 *nargs = arg_expand(ac);
422 argp = gchain;
423 gchain = schain;
424 }
425 {
426 register char **comargn;
427 register int argn;
428 register char **comargm;
429 argn = *nargs;
430 argn++; /* allow room to prepend interpreter name */
431 comargn=(char **) getstak(BYTESPERWORD*argn+BYTESPERWORD);
432 comargm = comargn += argn;
433 *comargn = ENDARGS;
434 while(argp)
435 {
436 *--comargn = argp->argval;
437 if((argp->argflag&A_RAW)==0)
438 trim(*comargn);
439 if((argp=argp->argchn)==0 || (argp->argflag&A_MAKE))
440 {
441 if((argn=comargm-comargn)>1)
442 gsort(comargn,argn);
443 comargm = comargn;
444 }
445 }
446 return(comargn);
447 }
448 }
449
450 #ifdef DEVFD
451 static FILE *to_close[15];
452
close_pipes()453 void close_pipes()
454 {
455 register FILE **fd = to_close;
456 while(*fd)
457 {
458 fclose(*fd);
459 *fd++ = NULL;
460 }
461 }
462 #endif /* DEVFD */
463
464 /* Argument list generation */
465
arg_expand(ac)466 static int arg_expand(ac)
467 COMPTR ac;
468 {
469 register ARGPTR argp;
470 register int count=0;
471 #ifdef DEVFD
472 int indx = 0;
473 close_pipes();
474 #endif /* DEVFD */
475 if(ac)
476 {
477 argp = ac->comarg;
478 while(argp)
479 {
480 argp->argflag &= ~A_MAKE;
481 #ifdef DEVFD
482 if(*argp->argval==0 && (argp->argflag&A_EXP))
483 {
484 /* argument of the form (cmd) */
485 register ARGPTR ap;
486 char *cp;
487 FILE *pv[2];
488 int fd;
489 ap = (ARGPTR)locstak();
490 ap->argflag |= A_MAKE;
491 ap->argflag &= ~A_RAW;
492 ap->argchn= gchain;
493 gchain = ap;
494 count++;
495 cp = movstr(devfd,ap->argval);
496 chkpipe(pv);
497 fd = argp->argflag&A_RAW;
498 endstak(movstr(itos(fileno(pv[fd])),cp));
499 if(fd)
500 execute((TREPTR)argp->argchn,states&ERRFLG,pv,(FILE**)0);
501 else
502 execute((TREPTR)argp->argchn,states&ERRFLG,(FILE**)0,pv);
503 #ifdef JOBS
504 jobstat.j_flag++;
505 #endif /* JOBS */
506 fclose(pv[1-fd]);
507 to_close[indx++] = pv[fd];
508 }
509 else
510 #endif /* DEVFD */
511 if((argp->argflag&A_RAW)==0)
512 {
513 register char *ap; ap = argp->argval;
514 if(argp->argflag&A_MAC)
515 ap = macro(ap);
516 count += split(ap,argp->argflag&A_MAC);
517 }
518 else
519 {
520 argp->argchn= gchain;
521 gchain = argp;
522 argp->argflag |= A_MAKE;
523 count++;
524 }
525 argp = argp->argnxt;
526 }
527 }
528 return(count);
529 }
530
split(s,macflg)531 static int split(s,macflg) /* blank interpretation routine */
532 char *s;
533 {
534 register char *argp;
535 register int c;
536 register ARGPTR ap;
537 int count=0;
538 int expflag = (is_option(NOGLOB)==0);
539 char *seps = (macflg?qvalup(IFSNOD):NULL);
540 if(seps==NULL || *seps==0)
541 seps = sptbnl;
542 while(1)
543 {
544 if(trapnote&SIGSET)
545 exitsh(SIGFAIL);
546 ap = (ARGPTR)locstak();
547 argp = ap->argval;
548 while(c= *s++)
549 {
550 if(c == ESCAPE)
551 {
552 c = *s++;
553 if(c!='/')
554 *argp++ = ESCAPE;
555 }
556 else if(strchr(seps,c))
557 break;
558 if(argp >= brkend)
559 setbrk(BRKINCR);
560 *argp++ = c;
561 }
562 /* This allows contiguous visible delimiters to count as delimiters */
563 if(argp==ap->argval)
564 {
565 if(c==0)
566 return(count);
567 if(macflg==0 || strchr(sptbnl,c))
568 continue;
569 }
570 else if(c==0)
571 {
572 s--;
573 }
574 /* file name generation */
575 endstak(argp);
576 ap->argflag &= ~(A_RAW|A_MAKE);
577 if(expflag && (c=expand(ap->argval,0)))
578 count += c;
579 else
580 {
581 count++;
582 ap->argchn= gchain;
583 gchain = ap;
584 }
585 gchain->argflag |= A_MAKE;
586 }
587 }
588