8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sh / macro.c
blob35101926a53e4280282de566aac882d9bab1bbe2
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
29 #pragma ident "%Z%%M% %I% %E% SMI"
31 * UNIX shell
34 #include "defs.h"
35 #include "sym.h"
36 #include <wait.h>
38 static unsigned char quote; /* used locally */
39 static unsigned char quoted; /* used locally */
40 static int getch();
41 static void comsubst(int);
42 static void flush(int);
44 static void
45 copyto(unsigned char endch, int trimflag)
46 /* trimflag - flag to check if argument will be trimmed */
48 unsigned int c;
49 unsigned int d;
50 unsigned char *pc;
52 while ((c = getch(endch, trimflag)) != endch && c)
53 if (quote) {
54 if(c == '\\') { /* don't interpret next character */
55 if (staktop >= brkend)
56 growstak(staktop);
57 pushstak(c);
58 d = readwc();
59 if(!escchar(d)) { /* both \ and following
60 character are quoted if next
61 character is not $, `, ", or \*/
62 if (staktop >= brkend)
63 growstak(staktop);
64 pushstak('\\');
65 if (staktop >= brkend)
66 growstak(staktop);
67 pushstak('\\');
68 pc = readw(d);
69 /* push entire multibyte char */
70 while(*pc) {
71 if (staktop >= brkend)
72 growstak(staktop);
73 pushstak(*pc++);
75 } else {
76 pc = readw(d);
77 /* d might be NULL */
78 /* Evenif d is NULL, we have to save it */
79 if (*pc) {
80 while (*pc) {
81 if (staktop >= brkend)
82 growstak(staktop);
83 pushstak(*pc++);
85 } else {
86 if (staktop >= brkend)
87 growstak(staktop);
88 pushstak(*pc);
91 } else { /* push escapes onto stack to quote characters */
92 pc = readw(c);
93 if (staktop >= brkend)
94 growstak(staktop);
95 pushstak('\\');
96 while(*pc) {
97 if (staktop >= brkend)
98 growstak(staktop);
99 pushstak(*pc++);
102 } else if(c == '\\') {
103 c = readwc(); /* get character to be escaped */
104 if (staktop >= brkend)
105 growstak(staktop);
106 pushstak('\\');
107 pc = readw(c);
108 /* c might be NULL */
109 /* Evenif c is NULL, we have to save it */
110 if (*pc) {
111 while (*pc) {
112 if (staktop >= brkend)
113 growstak(staktop);
114 pushstak(*pc++);
116 } else {
117 if (staktop >= brkend)
118 growstak(staktop);
119 pushstak(*pc);
121 } else {
122 pc = readw(c);
123 while (*pc) {
124 if (staktop >= brkend)
125 growstak(staktop);
126 pushstak(*pc++);
129 if (staktop >= brkend)
130 growstak(staktop);
131 zerostak();
132 if (c != endch)
133 error(badsub);
136 static void
137 skipto(unsigned char endch)
140 * skip chars up to }
142 unsigned int c;
144 while ((c = readwc()) && c != endch)
146 switch (c)
148 case SQUOTE:
149 skipto(SQUOTE);
150 break;
152 case DQUOTE:
153 skipto(DQUOTE);
154 break;
156 case DOLLAR:
157 if (readwc() == BRACE)
158 skipto('}');
161 if (c != endch)
162 error(badsub);
165 static
166 int getch(endch, trimflag)
167 unsigned char endch;
168 int trimflag; /* flag to check if an argument is going to be trimmed, here document
169 output is never trimmed
172 unsigned int d;
173 int atflag; /* flag to check if $@ has already been seen within double
174 quotes */
175 retry:
176 d = readwc();
177 if (!subchar(d))
178 return(d);
180 if (d == DOLLAR)
182 unsigned int c;
184 if ((c = readwc(), dolchar(c)))
186 struct namnod *n = (struct namnod *)NIL;
187 int dolg = 0;
188 BOOL bra;
189 BOOL nulflg;
190 unsigned char *argp, *v;
191 unsigned char idb[2];
192 unsigned char *id = idb;
194 if (bra = (c == BRACE))
195 c = readwc();
196 if (letter(c))
198 argp = (unsigned char *)relstak();
199 while (alphanum(c))
201 if (staktop >= brkend)
202 growstak(staktop);
203 pushstak(c);
204 c = readwc();
206 if (staktop >= brkend)
207 growstak(staktop);
208 zerostak();
209 n = lookup(absstak(argp));
210 setstak(argp);
211 if (n->namflg & N_FUNCTN)
212 error(badsub);
213 v = n->namval;
214 id = (unsigned char *)n->namid;
215 peekc = c | MARK;
217 else if (digchar(c))
219 *id = c;
220 idb[1] = 0;
221 if (astchar(c))
223 if(c == '@' && !atflag && quote) {
224 quoted--;
225 atflag = 1;
227 dolg = 1;
228 c = '1';
230 c -= '0';
231 v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0));
233 else if (c == '$')
234 v = pidadr;
235 else if (c == '!')
236 v = pcsadr;
237 else if (c == '#')
239 itos(dolc);
240 v = numbuf;
242 else if (c == '?')
244 itos(retval);
245 v = numbuf;
247 else if (c == '-')
248 v = flagadr;
249 else if (bra)
250 error(badsub);
251 else
252 goto retry;
253 c = readwc();
254 if (c == ':' && bra) /* null and unset fix */
256 nulflg = 1;
257 c = readwc();
259 else
260 nulflg = 0;
261 if (!defchar(c) && bra)
262 error(badsub);
263 argp = 0;
264 if (bra)
266 if (c != '}')
268 argp = (unsigned char *)relstak();
269 if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c)))
270 copyto('}', trimflag);
271 else
272 skipto('}');
273 argp = absstak(argp);
276 else
278 peekc = c | MARK;
279 c = 0;
281 if (v && (!nulflg || *v))
284 if (c != '+')
286 for (;;)
288 if (*v == 0 && quote) {
289 if (staktop >= brkend)
290 growstak(staktop);
291 pushstak('\\');
292 if (staktop >= brkend)
293 growstak(staktop);
294 pushstak('\0');
295 } else {
296 while (c = *v) {
297 wchar_t wc;
298 int length;
299 if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0)
300 length = 1;
302 if(quote || (c == '\\' && trimflag)) {
303 if (staktop >= brkend)
304 growstak(staktop);
305 pushstak('\\');
307 while(length-- > 0) {
308 if (staktop >= brkend)
309 growstak(staktop);
310 pushstak(*v++);
315 if (dolg == 0 || (++dolg > dolc))
316 break;
317 else /* $* and $@ expansion */
319 v = dolv[dolg];
320 if(*id == '*' && quote) {
321 /* push quoted space so that " $* " will not be broken into separate arguments */
322 if (staktop >= brkend)
323 growstak(staktop);
324 pushstak('\\');
326 if (staktop >= brkend)
327 growstak(staktop);
328 pushstak(' ');
333 else if (argp)
335 if (c == '?') {
336 if(trimflag)
337 trim(argp);
338 failed(id, *argp ? (const char *)argp :
339 badparam);
341 else if (c == '=')
343 if (n)
345 int strlngth = staktop - stakbot;
346 unsigned char *savptr = fixstak();
347 unsigned char *newargp;
349 * copy word onto stack, trim it, and then
350 * do assignment
352 usestak();
353 while(c = *argp) {
354 wchar_t wc;
355 int len;
357 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
358 len = 1;
360 if(c == '\\' && trimflag) {
361 argp++;
362 if (*argp == 0) {
363 argp++;
364 continue;
366 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
367 len = 1;
369 while(len-- > 0) {
370 if (staktop >= brkend)
371 growstak(staktop);
372 pushstak(*argp++);
375 newargp = fixstak();
376 assign(n, newargp);
377 tdystak(savptr);
378 (void) memcpystak(stakbot, savptr, strlngth);
379 staktop = stakbot + strlngth;
381 else
382 error(badsub);
385 else if (flags & setflg)
386 failed(id, unset);
387 goto retry;
389 else
390 peekc = c | MARK;
392 else if (d == endch)
393 return(d);
394 else if (d == SQUOTE)
396 comsubst(trimflag);
397 goto retry;
399 else if (d == DQUOTE && trimflag)
401 if(!quote) {
402 atflag = 0;
403 quoted++;
405 quote ^= QUOTE;
406 goto retry;
408 return(d);
411 unsigned char *
412 macro(as)
413 unsigned char *as;
416 * Strip "" and do $ substitution
417 * Leaves result on top of stack
419 BOOL savqu = quoted;
420 unsigned char savq = quote;
421 struct filehdr fb;
423 push(&fb);
424 estabf(as);
425 usestak();
426 quote = 0;
427 quoted = 0;
428 copyto(0, 1);
429 pop();
430 if (quoted && (stakbot == staktop)) {
431 if (staktop >= brkend)
432 growstak(staktop);
433 pushstak('\\');
434 if (staktop >= brkend)
435 growstak(staktop);
436 pushstak('\0');
438 * above is the fix for *'.c' bug
441 quote = savq;
442 quoted = savqu;
443 return(fixstak());
445 /* Save file descriptor for command substitution */
446 int savpipe = -1;
448 static void
449 comsubst(int trimflag)
450 /* trimflag - used to determine if argument will later be trimmed */
453 * command substn
455 struct fileblk cb;
456 unsigned int d;
457 int strlngth = staktop - stakbot;
458 unsigned char *oldstaktop;
459 unsigned char *savptr = fixstak();
460 unsigned char *pc;
462 usestak();
463 while ((d = readwc()) != SQUOTE && d) {
464 if(d == '\\') {
465 d = readwc();
466 if(!escchar(d) || (d == '"' && !quote)) {
467 /* trim quotes for `, \, or " if command substitution is within
468 double quotes */
469 if (staktop >= brkend)
470 growstak(staktop);
471 pushstak('\\');
474 pc = readw(d);
475 /* d might be NULL */
476 if (*pc) {
477 while (*pc) {
478 if (staktop >= brkend)
479 growstak(staktop);
480 pushstak(*pc++);
482 } else {
483 if (staktop >= brkend)
484 growstak(staktop);
485 pushstak(*pc);
489 unsigned char *argc;
491 argc = fixstak();
492 push(&cb);
493 estabf(argc); /* read from string */
496 struct trenod *t;
497 int pv[2];
500 * this is done like this so that the pipe
501 * is open only when needed
503 t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG ));
504 chkpipe(pv);
505 savpipe = pv[OTPIPE];
506 initf(pv[INPIPE]); /* read from pipe */
507 execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv);
508 close(pv[OTPIPE]);
509 savpipe = -1;
511 tdystak(savptr);
512 (void) memcpystak(stakbot, savptr, strlngth);
513 oldstaktop = staktop = stakbot + strlngth;
514 while (d = readwc()) {
515 if(quote || (d == '\\' && trimflag)) {
516 unsigned char *rest;
517 /* quote output from command subst. if within double
518 quotes or backslash part of output */
519 rest = readw(d);
520 if (staktop >= brkend)
521 growstak(staktop);
522 pushstak('\\');
523 while(d = *rest++) {
524 /* Pick up all of multibyte character */
525 if (staktop >= brkend)
526 growstak(staktop);
527 pushstak(d);
530 else {
531 pc = readw(d);
532 while (*pc) {
533 if (staktop >= brkend)
534 growstak(staktop);
535 pushstak(*pc++);
540 extern pid_t parent;
541 int stat;
542 int rc;
543 int ret = 0;
545 while ((ret = waitpid(parent,&stat,0)) != parent) {
546 /* break out if waitpid(2) has failed */
547 if (ret == -1)
548 break;
550 if (WIFEXITED(stat))
551 rc = WEXITSTATUS(stat);
552 else
553 rc = (WTERMSIG(stat) | SIGFLG);
554 if (rc && (flags & errflg))
555 exitsh(rc);
556 exitval = rc;
557 flags |= eflag;
558 exitset();
560 while (oldstaktop != staktop)
561 { /* strip off trailing newlines from command substitution only */
562 if ((*--staktop) != NL)
564 ++staktop;
565 break;
566 } else if(quote)
567 staktop--; /* skip past backslashes if quoting */
569 pop();
572 #define CPYSIZ 512
574 void
575 subst(int in, int ot)
577 unsigned int c;
578 struct fileblk fb;
579 int count = CPYSIZ;
580 unsigned char *pc;
582 push(&fb);
583 initf(in);
585 * DQUOTE used to stop it from quoting
587 while (c = (getch(DQUOTE, 0))) /* read characters from here document
588 and interpret them */
590 if(c == '\\') {
591 c = readwc(); /* check if character in here document is
592 escaped */
593 if(!escchar(c) || c == '"') {
594 if (staktop >= brkend)
595 growstak(staktop);
596 pushstak('\\');
599 pc = readw(c);
600 /* c might be NULL */
601 if (*pc) {
602 while (*pc) {
603 if (staktop >= brkend)
604 growstak(staktop);
605 pushstak(*pc++);
607 } else {
608 if (staktop >= brkend)
609 growstak(staktop);
610 pushstak(*pc);
612 if (--count == 0)
614 flush(ot);
615 count = CPYSIZ;
618 flush(ot);
619 pop();
622 static void
623 flush(int ot)
625 write(ot, stakbot, staktop - stakbot);
626 if (flags & execpr)
627 write(output, stakbot, staktop - stakbot);
628 staktop = stakbot;