2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
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 */
19 #include "sh.tconst.h"
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 */
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 */
57 void setDolp(tchar
*);
61 * Fix up the $ expansions and quotations in the
62 * argument list to command t.
65 Dfix(struct command
*t
)
71 tprintf("TRACE- Dfix()\n");
75 /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
76 for (pp
= t
->t_dcom
; p
= *pp
++; )
78 if (cmap(*p
++, _DOL
|QUOTES
)) { /* $, \, ', ", ` */
79 Dfix2(t
->t_dcom
); /* found one */
88 * $ substitute one word, for i/o redirection
96 tprintf("TRACE- Dfix1()\n");
100 Dv
[0] = cp
; Dv
[1] = NOSTR
;
106 cp
= savestr(gargv
[0]);
107 blkfree(gargv
), gargv
= 0;
112 * Subroutine to do actual fixing after state initialization.
117 tchar
*agargv
[GAVSIZ
];
120 tprintf("TRACE- Dfix2()\n");
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 (...) */
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.
141 static tchar
*wbuf
= NULL
;
142 static int wbufsiz
= BUFSIZ
;
146 #define DYNAMICBUFFER() \
148 if (wp >= wbufsiz) { \
150 wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
155 tprintf("TRACE- Dword()\n");
158 wbuf
= xalloc((wbufsiz
+1) * sizeof (tchar
));
167 /* finish this word and catch the code above the next time */
180 /* We preserve ` quotations which are done yet later */
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.
190 dolflg
= c1
== '"' ? DODOL
: 0;
195 if (c
== '\n' || c
== DEOF
)
196 error("Unmatched %c", (tchar
) c1
);
197 if ((c
& (QUOTE
|TRIM
)) == ('\n' | QUOTE
))
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
;
212 /* Prevent all further interpretation */
213 wbuf
[wp
++] = c
| QUOTE
;
217 /* Leave all text alone for later */
226 goto pack
; /* continue the word */
229 c
= DgetC(0); /* No $ subst! */
230 if (c
== '\n' || c
== DEOF
)
234 #ifdef MBCHAR /* Could be a space char from aux. codeset. */
236 if (isauxsp(c
)) goto loop
;
242 /* pack up more characters in this word */
256 if (cmap(c
, _SP
|_NL
|_Q
|_Q1
) ||
257 isauxsp(c
)) { /* sp \t\n'"` or aux. sp */
269 Gcat(S_
/* "" */, wbuf
);
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.
289 c
= *lap
++ & (QUOTE
|TRIM
);
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
))
305 if (c
= *dolp
++ & (QUOTE
|TRIM
))
320 if (c
== '$' && flag
) {
327 tchar
*nulvec
[] = { 0 };
328 struct varent nulargv
= { nulvec
, S_argv
, 0 };
331 * Handle the multitudinous $ expansion forms.
339 tchar name
[MAX_VREF_LEN
];
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 */
346 tprintf("TRACE- Dgetdol()\n");
348 dolmod
= dolmcnt
= 0;
351 c
= DgetC(0); /* sc is { to take } later */
352 if ((c
& TRIM
) == '#')
353 dimen
++, c
= DgetC(0); /* $# takes dimension */
355 bitset
++, c
= DgetC(0); /* $? tests existence */
361 error("Variable syntax"); /* No $?$, $#$ */
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')
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.
393 (void) strcpy_(name
, S_argv
);
395 subscr
= -1; /* Prevent eating [...] */
402 goto syntax
; /* No $#1, e.g. */
405 subscr
= subscr
* 10 + c
- '0';
410 error("Subscript out of range");
413 dolp
= file
? S_1
/* "1" */ : S_0
/* "0" */;
417 error("No file for $0");
437 /* if variable name is > 20, complain */
438 if (np
>= &name
[MAX_VAR_LEN
])
439 error("Variable name too long");
448 * getenv() to getenv_(), because 'name''s type is now tchar *
451 dolp
= (vp
|| getenv_(name
)) ? S_1
/* "1" */ : S_0
/* "0" */;
456 * getenv() to getenv_(), because 'name''s type is now tchar *
468 upb
= blklen(vp
->vec
);
469 if (dimen
== 0 && subscr
== 0 && c
== '[') {
472 c
= DgetC(DODOL
); /* Allow $ expand within [ ] */
475 if (c
== '\n' || c
== DEOF
)
477 if (np
>= &name
[MAX_VREF_LEN
])
478 error("Variable reference too long");
482 if (dolp
|| dolcnt
) /* $ exp must end before ] */
490 i
= i
* 10 + *np
++ - '0';
491 /* if ((i < 0 || i > upb) && !any(*np, "-*")) { */
492 if ((i
< 0 || i
> upb
) && (*np
!= '-') && (*np
!= '*')) {
495 error("Subscript out of range");
499 upb
= lwb
, np
= S_AST
/* "*" */;
512 i
= i
* 10 + *np
++ - '0';
513 if (i
< 0 || i
> upb
)
537 tchar
*cp
= putn(upb
- lwb
+ 1);
545 c
= DgetC(0), dolmcnt
= 1;
547 c
= DgetC(0), dolmcnt
= 10000;
548 if (!any(c
, S_htrqxe
))
549 error("Bad : mod in $");
555 dolnxt
= &vp
->vec
[lwb
- 1];
556 dolcnt
= upb
- lwb
+ 1;
572 tprintf("TRACE- setDolp()\n");
574 if (dolmod
== 0 || dolmcnt
== 0) {
578 dp
= domod(cp
, dolmod
);
604 if (Dcp
&& (c
= *Dcp
++))
605 return (c
&(QUOTE
|TRIM
));
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.
632 tchar obuf
[BUFSIZ
], lbuf
[BUFSIZ
], mbuf
[BUFSIZ
];
633 int ocnt
, lcnt
, mcnt
;
634 tchar
*lbp
, *obp
, *mbp
;
637 tchar shtemp
[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
642 tprintf("TRACE- heredoc()\n");
644 if ((fd1
= mkstemp_(shtemp
)) < 0)
646 (void) unlink_(shtemp
); /* 0 0 inode! */
648 Dv
[0] = term
; Dv
[1] = NOSTR
; gflag
= 0;
649 trim(Dv
); rscan(Dv
, Dtestq
); quoted
= gflag
;
650 ocnt
= BUFSIZ
; obp
= obuf
;
655 lbp
= lbuf
; lcnt
= BUFSIZ
- 4;
657 c
= readc(1); /* 1 -> Want EOF returns */
660 bferr("<< terminator not found");
667 setname(S_LESLES
/* "<<" */);
668 error("Line overflow");
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);
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
++; ) {
691 (void) write_(0, obuf
, BUFSIZ
);
692 obp
= obuf
; ocnt
= BUFSIZ
;
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;
707 if ((c
&= TRIM
) == 0)
709 /* \ quotes \ $ ` here */
712 /* if (!any(c, "$\\`")) */
713 if ((c
!= '$') && (c
!= '\\') && (c
!= '`'))
714 unDgetC(c
| QUOTE
), c
= '\\';
720 setname(S_LESLES
/* "<<" */);
721 bferr("Line overflow");
727 * If any ` in line do command substitution
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)
737 vp
= dobackp(mbuf
, 1);
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
751 for (mbp
= *vp
; *mbp
; mbp
++) {
752 *obp
++ = *mbp
& TRIM
;
754 (void) write_(0, obuf
, BUFSIZ
);
755 obp
= obuf
; ocnt
= BUFSIZ
;
760 (void) write_(0, obuf
, BUFSIZ
);
761 obp
= obuf
; ocnt
= BUFSIZ
;
765 blkfree(pargv
), pargv
= 0;