xref: /original-bsd/local/toolchest/ksh/sh/args.c (revision e21485a6)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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