8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / csh / sh.dol.c
blobfe0b88f4b067352eba9109e91a267bfcb1157ee0
1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include <unistd.h> /* for lseek prototype */
18 #include "sh.h"
19 #include "sh.tconst.h"
22 * C shell
26 * These routines perform variable substitution and quoting via ' and ".
27 * To this point these constructs have been preserved in the divided
28 * input words. Here we expand variables and turn quoting via ' and " into
29 * QUOTE bits on characters (which prevent further interpretation).
30 * If the `:q' modifier was applied during history expansion, then
31 * some QUOTEing may have occurred already, so we dont "trim()" here.
34 int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
35 tchar *Dcp, **Dvp; /* Input vector for Dreadc */
37 #define DEOF -1
39 #define unDgetC(c) Dpeekc = c
41 #define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */
44 * The following variables give the information about the current
45 * $ expansion, recording the current word position, the remaining
46 * words within this expansion, the count of remaining words, and the
47 * information about any : modifier which is being applied.
49 tchar *dolp; /* Remaining chars from this word */
50 tchar **dolnxt; /* Further words */
51 int dolcnt; /* Count of further words */
52 tchar dolmod; /* : modifier character */
53 int dolmcnt; /* :gx -> 10000, else 1 */
55 void Dfix2(tchar **);
56 void Dgetdol(void);
57 void setDolp(tchar *);
58 void unDredc(int);
61 * Fix up the $ expansions and quotations in the
62 * argument list to command t.
64 void
65 Dfix(struct command *t)
67 tchar **pp;
68 tchar *p;
70 #ifdef TRACE
71 tprintf("TRACE- Dfix()\n");
72 #endif
73 if (noexec)
74 return;
75 /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
76 for (pp = t->t_dcom; p = *pp++; )
77 while (*p)
78 if (cmap(*p++, _DOL|QUOTES)) { /* $, \, ', ", ` */
79 Dfix2(t->t_dcom); /* found one */
80 blkfree(t->t_dcom);
81 t->t_dcom = gargv;
82 gargv = 0;
83 return;
88 * $ substitute one word, for i/o redirection
90 tchar *
91 Dfix1(tchar *cp)
93 tchar *Dv[2];
95 #ifdef TRACE
96 tprintf("TRACE- Dfix1()\n");
97 #endif
98 if (noexec)
99 return (0);
100 Dv[0] = cp; Dv[1] = NOSTR;
101 Dfix2(Dv);
102 if (gargc != 1) {
103 setname(cp);
104 bferr("Ambiguous");
106 cp = savestr(gargv[0]);
107 blkfree(gargv), gargv = 0;
108 return (cp);
112 * Subroutine to do actual fixing after state initialization.
114 void
115 Dfix2(tchar **v)
117 tchar *agargv[GAVSIZ];
119 #ifdef TRACE
120 tprintf("TRACE- Dfix2()\n");
121 #endif
122 ginit(agargv); /* Initialize glob's area pointers */
123 Dvp = v; Dcp = S_ /* "" */; /* Setup input vector for Dreadc */
124 unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */
125 dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */
126 while (Dword())
127 continue;
128 gargv = copyblk(gargv);
132 * Get a word. This routine is analogous to the routine
133 * word() in sh.lex.c for the main lexical input. One difference
134 * here is that we don't get a newline to terminate our expansion.
135 * Rather, DgetC will return a DEOF when we hit the end-of-input.
138 Dword(void)
140 int c, c1;
141 static tchar *wbuf = NULL;
142 static int wbufsiz = BUFSIZ;
143 int wp = 0;
144 bool dolflg;
145 bool sofar = 0;
146 #define DYNAMICBUFFER() \
147 do { \
148 if (wp >= wbufsiz) { \
149 wbufsiz += BUFSIZ; \
150 wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
152 } while (0)
154 #ifdef TRACE
155 tprintf("TRACE- Dword()\n");
156 #endif
157 if (wbuf == NULL)
158 wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
159 loop:
160 c = DgetC(DODOL);
161 switch (c) {
163 case DEOF:
164 deof:
165 if (sofar == 0)
166 return (0);
167 /* finish this word and catch the code above the next time */
168 unDredc(c);
169 /* fall into ... */
171 case '\n':
172 wbuf[wp] = 0;
173 goto ret;
175 case ' ':
176 case '\t':
177 goto loop;
179 case '`':
180 /* We preserve ` quotations which are done yet later */
181 wbuf[wp++] = c;
182 case '\'':
183 case '"':
185 * Note that DgetC never returns a QUOTES character
186 * from an expansion, so only true input quotes will
187 * get us here or out.
189 c1 = c;
190 dolflg = c1 == '"' ? DODOL : 0;
191 for (;;) {
192 c = DgetC(dolflg);
193 if (c == c1)
194 break;
195 if (c == '\n' || c == DEOF)
196 error("Unmatched %c", (tchar) c1);
197 if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
198 --wp;
199 DYNAMICBUFFER();
200 switch (c1) {
202 case '"':
204 * Leave any `s alone for later.
205 * Other chars are all quoted, thus `...`
206 * can tell it was within "...".
208 wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
209 break;
211 case '\'':
212 /* Prevent all further interpretation */
213 wbuf[wp++] = c | QUOTE;
214 break;
216 case '`':
217 /* Leave all text alone for later */
218 wbuf[wp++] = c;
219 break;
222 if (c1 == '`') {
223 DYNAMICBUFFER();
224 wbuf[wp++] = '`';
226 goto pack; /* continue the word */
228 case '\\':
229 c = DgetC(0); /* No $ subst! */
230 if (c == '\n' || c == DEOF)
231 goto loop;
232 c |= QUOTE;
233 break;
234 #ifdef MBCHAR /* Could be a space char from aux. codeset. */
235 default:
236 if (isauxsp(c)) goto loop;
237 #endif /* MBCHAR */
239 unDgetC(c);
240 pack:
241 sofar = 1;
242 /* pack up more characters in this word */
243 for (;;) {
244 c = DgetC(DODOL);
245 if (c == '\\') {
246 c = DgetC(0);
247 if (c == DEOF)
248 goto deof;
249 if (c == '\n')
250 c = ' ';
251 else
252 c |= QUOTE;
254 if (c == DEOF)
255 goto deof;
256 if (cmap(c, _SP|_NL|_Q|_Q1) ||
257 isauxsp(c)) { /* sp \t\n'"` or aux. sp */
258 unDgetC(c);
259 if (cmap(c, QUOTES))
260 goto loop;
261 DYNAMICBUFFER();
262 wbuf[wp++] = 0;
263 goto ret;
265 DYNAMICBUFFER();
266 wbuf[wp++] = c;
268 ret:
269 Gcat(S_ /* "" */, wbuf);
270 return (1);
274 * Get a character, performing $ substitution unless flag is 0.
275 * Any QUOTES character which is returned from a $ expansion is
276 * QUOTEd so that it will not be recognized above.
279 DgetC(int flag)
281 int c;
283 top:
284 if (c = Dpeekc) {
285 Dpeekc = 0;
286 return (c);
288 if (lap) {
289 c = *lap++ & (QUOTE|TRIM);
290 if (c == 0) {
291 lap = 0;
292 goto top;
294 quotspec:
296 * don't quote things if there was an error (err!=0)
297 * the input is original, not from a substitution and
298 * therefore should not be quoted
300 if (!err && cmap(c, QUOTES))
301 return (c | QUOTE);
302 return (c);
304 if (dolp) {
305 if (c = *dolp++ & (QUOTE|TRIM))
306 goto quotspec;
307 if (dolcnt > 0) {
308 setDolp(*dolnxt++);
309 --dolcnt;
310 return (' ');
312 dolp = 0;
314 if (dolcnt > 0) {
315 setDolp(*dolnxt++);
316 --dolcnt;
317 goto top;
319 c = Dredc();
320 if (c == '$' && flag) {
321 Dgetdol();
322 goto top;
324 return (c);
327 tchar *nulvec[] = { 0 };
328 struct varent nulargv = { nulvec, S_argv, 0 };
331 * Handle the multitudinous $ expansion forms.
332 * Ugh.
334 void
335 Dgetdol(void)
337 tchar *np;
338 struct varent *vp;
339 tchar name[MAX_VREF_LEN];
340 int c, sc;
341 int subscr = 0, lwb = 1, upb = 0;
342 bool dimen = 0, bitset = 0;
343 tchar wbuf[BUFSIZ + MB_LEN_MAX]; /* read_ may return extra bytes */
345 #ifdef TRACE
346 tprintf("TRACE- Dgetdol()\n");
347 #endif
348 dolmod = dolmcnt = 0;
349 c = sc = DgetC(0);
350 if (c == '{')
351 c = DgetC(0); /* sc is { to take } later */
352 if ((c & TRIM) == '#')
353 dimen++, c = DgetC(0); /* $# takes dimension */
354 else if (c == '?')
355 bitset++, c = DgetC(0); /* $? tests existence */
356 switch (c) {
358 case '$':
359 if (dimen || bitset)
360 syntax:
361 error("Variable syntax"); /* No $?$, $#$ */
362 setDolp(doldol);
363 goto eatbrac;
365 case '<'|QUOTE:
366 if (dimen || bitset)
367 goto syntax; /* No $?<, $#< */
368 for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
369 if (np >= &wbuf[BUFSIZ-1])
370 error("$< line too long");
371 if (*np <= 0 || *np == '\n')
372 break;
374 *np = 0;
376 * KLUDGE: dolmod is set here because it will
377 * cause setDolp to call domod and thus to copy wbuf.
378 * Otherwise setDolp would use it directly. If we saved
379 * it ourselves, no one would know when to free it.
380 * The actual function of the 'q' causes filename
381 * expansion not to be done on the interpolated value.
383 dolmod = 'q';
384 dolmcnt = 10000;
385 setDolp(wbuf);
386 goto eatbrac;
388 case DEOF:
389 case '\n':
390 goto syntax;
392 case '*':
393 (void) strcpy_(name, S_argv);
394 vp = adrof(S_argv);
395 subscr = -1; /* Prevent eating [...] */
396 break;
398 default:
399 np = name;
400 if (digit(c)) {
401 if (dimen)
402 goto syntax; /* No $#1, e.g. */
403 subscr = 0;
404 do {
405 subscr = subscr * 10 + c - '0';
406 c = DgetC(0);
407 } while (digit(c));
408 unDredc(c);
409 if (subscr < 0)
410 error("Subscript out of range");
411 if (subscr == 0) {
412 if (bitset) {
413 dolp = file ? S_1 /* "1" */ : S_0 /* "0" */;
414 goto eatbrac;
416 if (file == 0)
417 error("No file for $0");
418 setDolp(file);
419 goto eatbrac;
421 if (bitset)
422 goto syntax;
423 vp = adrof(S_argv);
424 if (vp == 0) {
425 vp = &nulargv;
426 goto eatmod;
428 break;
430 if (!alnum(c))
431 goto syntax;
432 for (;;) {
433 *np++ = c;
434 c = DgetC(0);
435 if (!alnum(c))
436 break;
437 /* if variable name is > 20, complain */
438 if (np >= &name[MAX_VAR_LEN])
439 error("Variable name too long");
442 *np++ = 0;
443 unDredc(c);
444 vp = adrof(name);
446 if (bitset) {
448 * getenv() to getenv_(), because 'name''s type is now tchar *
449 * no need to xalloc
451 dolp = (vp || getenv_(name)) ? S_1 /* "1" */ : S_0 /* "0" */;
452 goto eatbrac;
454 if (vp == 0) {
456 * getenv() to getenv_(), because 'name''s type is now tchar *
457 * no need to xalloc
459 np = getenv_(name);
460 if (np) {
461 addla(np);
462 goto eatbrac;
464 udvar(name);
465 /*NOTREACHED*/
467 c = DgetC(0);
468 upb = blklen(vp->vec);
469 if (dimen == 0 && subscr == 0 && c == '[') {
470 np = name;
471 for (;;) {
472 c = DgetC(DODOL); /* Allow $ expand within [ ] */
473 if (c == ']')
474 break;
475 if (c == '\n' || c == DEOF)
476 goto syntax;
477 if (np >= &name[MAX_VREF_LEN])
478 error("Variable reference too long");
479 *np++ = c;
481 *np = 0, np = name;
482 if (dolp || dolcnt) /* $ exp must end before ] */
483 goto syntax;
484 if (!*np)
485 goto syntax;
486 if (digit(*np)) {
487 int i = 0;
489 while (digit(*np))
490 i = i * 10 + *np++ - '0';
491 /* if ((i < 0 || i > upb) && !any(*np, "-*")) { */
492 if ((i < 0 || i > upb) && (*np != '-') && (*np != '*')) {
493 oob:
494 setname(vp->v_name);
495 error("Subscript out of range");
497 lwb = i;
498 if (!*np)
499 upb = lwb, np = S_AST /* "*" */;
501 if (*np == '*')
502 np++;
503 else if (*np != '-')
504 goto syntax;
505 else {
506 int i = upb;
508 np++;
509 if (digit(*np)) {
510 i = 0;
511 while (digit(*np))
512 i = i * 10 + *np++ - '0';
513 if (i < 0 || i > upb)
514 goto oob;
516 if (i < lwb)
517 upb = lwb - 1;
518 else
519 upb = i;
521 if (lwb == 0) {
522 if (upb != 0)
523 goto oob;
524 upb = -1;
526 if (*np)
527 goto syntax;
528 } else {
529 if (subscr > 0)
530 if (subscr > upb)
531 lwb = 1, upb = 0;
532 else
533 lwb = upb = subscr;
534 unDredc(c);
536 if (dimen) {
537 tchar *cp = putn(upb - lwb + 1);
539 addla(cp);
540 xfree(cp);
541 } else {
542 eatmod:
543 c = DgetC(0);
544 if (c == ':') {
545 c = DgetC(0), dolmcnt = 1;
546 if (c == 'g')
547 c = DgetC(0), dolmcnt = 10000;
548 if (!any(c, S_htrqxe))
549 error("Bad : mod in $");
550 dolmod = c;
551 if (c == 'q')
552 dolmcnt = 10000;
553 } else
554 unDredc(c);
555 dolnxt = &vp->vec[lwb - 1];
556 dolcnt = upb - lwb + 1;
558 eatbrac:
559 if (sc == '{') {
560 c = Dredc();
561 if (c != '}')
562 goto syntax;
566 void
567 setDolp(tchar *cp)
569 tchar *dp;
571 #ifdef TRACE
572 tprintf("TRACE- setDolp()\n");
573 #endif
574 if (dolmod == 0 || dolmcnt == 0) {
575 dolp = cp;
576 return;
578 dp = domod(cp, dolmod);
579 if (dp) {
580 dolmcnt--;
581 addla(dp);
582 xfree(dp);
583 } else
584 addla(cp);
585 dolp = S_ /* "" */;
588 void
589 unDredc(int c)
592 Dpeekrd = c;
596 Dredc()
598 int c;
600 if (c = Dpeekrd) {
601 Dpeekrd = 0;
602 return (c);
604 if (Dcp && (c = *Dcp++))
605 return (c&(QUOTE|TRIM));
606 if (*Dvp == 0) {
607 Dcp = 0;
608 return (DEOF);
610 Dcp = *Dvp++;
611 return (' ');
614 void
615 Dtestq(int c)
618 if (cmap(c, QUOTES))
619 gflag = 1;
623 * Form a shell temporary file (in unit 0) from the words
624 * of the shell input up to a line the same as "term".
625 * Unit 0 should have been closed before this call.
627 void
628 heredoc(tchar *term)
630 int c;
631 tchar *Dv[2];
632 tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
633 int ocnt, lcnt, mcnt;
634 tchar *lbp, *obp, *mbp;
635 tchar **vp;
636 bool quoted;
637 tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
638 'X', 'X', 'X', 0};
639 int fd1;
641 #ifdef TRACE
642 tprintf("TRACE- heredoc()\n");
643 #endif
644 if ((fd1 = mkstemp_(shtemp)) < 0)
645 Perror(shtemp);
646 (void) unlink_(shtemp); /* 0 0 inode! */
647 unsetfd(fd1);
648 Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
649 trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
650 ocnt = BUFSIZ; obp = obuf;
651 for (;;) {
653 * Read up a line
655 lbp = lbuf; lcnt = BUFSIZ - 4;
656 for (;;) {
657 c = readc(1); /* 1 -> Want EOF returns */
658 if (c < 0) {
659 setname(term);
660 bferr("<< terminator not found");
662 if (c == '\n')
663 break;
664 if (c &= TRIM) {
665 *lbp++ = c;
666 if (--lcnt < 0) {
667 setname(S_LESLES /* "<<" */);
668 error("Line overflow");
672 *lbp = 0;
675 * Compare to terminator -- before expansion
677 if (eq(lbuf, term)) {
678 (void) write_(0, obuf, BUFSIZ - ocnt);
679 (void) lseek(0, (off_t)0, 0);
680 return;
684 * If term was quoted or -n just pass it on
686 if (quoted || noexec) {
687 *lbp++ = '\n'; *lbp = 0;
688 for (lbp = lbuf; c = *lbp++; ) {
689 *obp++ = c;
690 if (--ocnt == 0) {
691 (void) write_(0, obuf, BUFSIZ);
692 obp = obuf; ocnt = BUFSIZ;
695 continue;
699 * Term wasn't quoted so variable and then command
700 * expand the input line
702 Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
703 for (;;) {
704 c = DgetC(DODOL);
705 if (c == DEOF)
706 break;
707 if ((c &= TRIM) == 0)
708 continue;
709 /* \ quotes \ $ ` here */
710 if (c == '\\') {
711 c = DgetC(0);
712 /* if (!any(c, "$\\`")) */
713 if ((c != '$') && (c != '\\') && (c != '`'))
714 unDgetC(c | QUOTE), c = '\\';
715 else
716 c |= QUOTE;
718 *mbp++ = c;
719 if (--mcnt == 0) {
720 setname(S_LESLES /* "<<" */);
721 bferr("Line overflow");
724 *mbp++ = 0;
727 * If any ` in line do command substitution
729 mbp = mbuf;
730 if (any('`', mbp)) {
732 * 1 arg to dobackp causes substitution to be literal.
733 * Words are broken only at newlines so that all blanks
734 * and tabs are preserved. Blank lines (null words)
735 * are not discarded.
737 vp = dobackp(mbuf, 1);
738 } else
739 /* Setup trivial vector similar to return of dobackp */
740 Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
743 * Resurrect the words from the command substitution
744 * each separated by a newline. Note that the last
745 * newline of a command substitution will have been
746 * discarded, but we put a newline after the last word
747 * because this represents the newline after the last
748 * input line!
750 for (; *vp; vp++) {
751 for (mbp = *vp; *mbp; mbp++) {
752 *obp++ = *mbp & TRIM;
753 if (--ocnt == 0) {
754 (void) write_(0, obuf, BUFSIZ);
755 obp = obuf; ocnt = BUFSIZ;
758 *obp++ = '\n';
759 if (--ocnt == 0) {
760 (void) write_(0, obuf, BUFSIZ);
761 obp = obuf; ocnt = BUFSIZ;
764 if (pargv)
765 blkfree(pargv), pargv = 0;