1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23 /*
24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 #if defined(sun)
32 #pragma ident "@(#)macro.c 1.16 06/10/09 SMI"
33 #endif
34
35 #include "defs.h"
36
37 /*
38 * Copyright 2008-2021 J. Schilling
39 *
40 * @(#)macro.c 1.102 21/07/21 2008-2021 J. Schilling
41 */
42 #ifndef lint
43 static UConst char sccsid[] =
44 "@(#)macro.c 1.102 21/07/21 2008-2021 J. Schilling";
45 #endif
46
47 /*
48 * UNIX shell
49 */
50
51 #ifdef SCHILY_INCLUDES
52 #include "sym.h"
53 #include <schily/param.h>
54 #include <schily/wait.h>
55 #else
56 #include "sym.h"
57 #include <sys/param.h>
58 #include <wait.h>
59 #endif
60
61 #ifndef MAXPATHLEN
62 #define MAXPATHLEN 1024
63 #endif
64
65 #define no_pipe (int *)0
66
67 int macflag;
68 static unsigned char quote; /* used locally */
69 static unsigned char quoted; /* used locally */
70
71 #define COM_BACKQUOTE 0 /* `command` type command substitution */
72 #define COM_DOL_PAREN 1 /* $(command) type command substitution */
73
74 static void copyto __PR((unsigned char endch, int trimflag));
75 static void skipto __PR((unsigned char endch));
76 #ifdef DO_DOT_SH_PARAMS
77 static unsigned char *shvar __PR((unsigned char *v));
78 #endif
79 static unsigned int dolname __PR((unsigned char **argpp,
80 unsigned int c, unsigned int addc));
81 static int getch __PR((unsigned char endch, int trimflag));
82 unsigned char *macro __PR((unsigned char *as));
83 unsigned char *_macro __PR((unsigned char *as));
84 static void comsubst __PR((int, int));
85 void subst __PR((int in, int ot));
86 static void flush __PR((int));
87
88 #ifdef DO_SUBSTRING
89 static int mbschars __PR((unsigned char *v));
90 static unsigned char *prefsubstr __PR((unsigned char *v, unsigned char *pat,
91 int largest));
92 static unsigned char *mbdecr __PR((unsigned char *s, unsigned char *sp));
93 static int suffsubstr __PR((unsigned char *v, unsigned char *pat,
94 int largest));
95 #ifdef __needed__
96 static Uchar *globesc __PR((Uchar *argp));
97 #endif
98 #endif
99 static void sizecpy __PR((int vsize, Uchar *v, int trimflag));
100 static Uchar *trimcpy __PR((Uchar *argp, int trimflag));
101
102 #ifdef PROTOTYPES
103 static void
copyto(unsigned char endch,int trimflag)104 copyto(unsigned char endch, int trimflag)
105 #else
106 static void
107 copyto(endch, trimflag)
108 unsigned char endch;
109 int trimflag;
110 #endif
111 /* trimflag - flag to check if argument will be trimmed */
112 {
113 unsigned int c;
114 unsigned int d;
115 unsigned char *pc;
116
117 while ((c = getch(endch, trimflag)) != endch && c) {
118 if (quote) {
119 if (c == '\\') { /* don't interpret next character */
120 GROWSTAKTOP();
121 pushstak(c);
122 d = readwc();
123 if (!escchar(d)) {
124 /*
125 * both \ and following
126 * character are quoted if next
127 * character is not $, `, ", or \
128 */
129 GROWSTAKTOP();
130 pushstak('\\');
131 GROWSTAKTOP();
132 pushstak('\\');
133 }
134 pc = readw(d);
135 /*
136 * d might be NULL
137 * Even if d is NULL, we have to save it
138 */
139 if (*pc) {
140 while (*pc) {
141 GROWSTAKTOP();
142 pushstak(*pc++);
143 }
144 } else {
145 GROWSTAKTOP();
146 pushstak(*pc);
147 }
148 } else { /* push escapes onto stack to quote chars */
149 pc = readw(c);
150 GROWSTAKTOP();
151 pushstak('\\');
152 while (*pc) {
153 GROWSTAKTOP();
154 pushstak(*pc++);
155 }
156 }
157 } else if (c == '\\') {
158 c = readwc(); /* get character to be escaped */
159 GROWSTAKTOP();
160 pushstak('\\');
161 pc = readw(c);
162 /* c might be NULL */
163 /* Evenif c is NULL, we have to save it */
164 if (*pc) {
165 while (*pc) {
166 GROWSTAKTOP();
167 pushstak(*pc++);
168 }
169 } else {
170 GROWSTAKTOP();
171 pushstak(*pc);
172 }
173 } else {
174 pc = readw(c);
175 while (*pc) {
176 GROWSTAKTOP();
177 pushstak(*pc++);
178 }
179 }
180 }
181 GROWSTAKTOP();
182 zerostak(); /* Add nul byte */
183 if (c != endch)
184 error(badsub);
185 }
186
187 #ifdef PROTOTYPES
188 static void
skipto(unsigned char endch)189 skipto(unsigned char endch)
190 #else
191 static void
192 skipto(endch)
193 unsigned char endch;
194 #endif
195 {
196 /*
197 * skip chars up to }
198 */
199 unsigned int c;
200
201 while ((c = readwc()) != '\0' && c != endch) {
202 switch (c) {
203 case SQUOTE:
204 skipto(SQUOTE);
205 break;
206
207 case DQUOTE:
208 skipto(DQUOTE);
209 break;
210
211 case DOLLAR:
212 if ((c = readwc()) == BRACE)
213 skipto('}');
214 else if (c == SQUOTE || c == DQUOTE)
215 skipto(c);
216 else if (c == 0)
217 goto out;
218 break;
219
220 case ESCAPE:
221 if (!(c = readwc()))
222 goto out;
223 }
224 }
225 out:
226 if (c != endch)
227 error(badsub);
228 }
229
230 /*
231 * Expand special shell variables ${.sh.xxx}.
232 */
233 #ifdef DO_DOT_SH_PARAMS
234 static unsigned char *
shvar(v)235 shvar(v)
236 unsigned char *v;
237 {
238 if (eq(v, "status")) { /* exit status */
239 sitos(retex.ex_status);
240 v = numbuf;
241 } else if (eq(v, "termsig")) { /* kill signame */
242 numbuf[0] = '\0';
243 sig2str(retex.ex_status, (char *)numbuf);
244 v = numbuf;
245 if (numbuf[0] == '\0')
246 strcpy((char *)numbuf, "UNKNOWN");
247 } else if (eq(v, "code")) { /* exit code (reason) */
248 itos(retex.ex_code);
249 v = numbuf;
250 } else if (eq(v, "codename")) { /* text for above */
251 v = UC code2str(retex.ex_code);
252 } else if (eq(v, "pid")) { /* exited pid */
253 itos(retex.ex_pid);
254 v = numbuf;
255 } else if (eq(v, "signo")) { /* SIGCHLD or trapsig */
256 itos(retex.ex_signo);
257 v = numbuf;
258 } else if (eq(v, "signame")) { /* text for above */
259 sig2str(retex.ex_signo, (char *)numbuf);
260 v = numbuf;
261 } else if (eq(v, "shell")) { /* Shell implementation name */
262 v = UC shname;
263 } else if (eq(v, "version")) { /* Shell version */
264 v = UC shvers;
265 } else if (eq(v, "path")) { /* Shell path */
266 static unsigned char *shpath = NULL;
267 char pbuf[MAXPATHLEN + 1];
268 unsigned char *pname;
269 #ifdef HAVE_GETEXECNAME
270 const char *exname = getexecname();
271 #else
272 char *exname = getexecpath();
273 #endif
274 if (shpath)
275 return (shpath);
276 if (exname == NULL)
277 return (NULL);
278 if (*exname == '/') {
279 pname = UC exname;
280 } else {
281 #ifdef HAVE_REALPATH
282 pname = UC realpath(exname, pbuf);
283 #else
284 pname = UC abspath(exname, pbuf, sizeof (pbuf));
285 #endif
286 }
287 if (pname) {
288 /*
289 * NUMBUFLEN is sufficient in most cases.
290 * We cannot do this on stak as we need to
291 * keep the current stak segment open.
292 */
293 if (length(pname) > NUMBUFLEN) {
294 shpath = pname = make(pname);
295 } else {
296 movstr(pname, numbuf);
297 return (numbuf);
298 }
299 }
300 #ifndef HAVE_GETEXECNAME
301 libc_free(exname);
302 #endif
303 v = UC pname;
304 } else {
305 return (NULL);
306 }
307 return (v);
308 }
309 #endif
310
311 /*
312 * Collect the parameter name.
313 * If "addc" is null, collect a normal parameter name,
314 * else "addc" is an additional permitted character.
315 * This is typically '.' for the ".sh.xxx" parameters.
316 * Returns the first non-matching character to allow the rest
317 * of the parser to recover.
318 */
319 static unsigned int
dolname(argpp,c,addc)320 dolname(argpp, c, addc)
321 unsigned char **argpp;
322 unsigned int c;
323 unsigned int addc;
324 {
325 unsigned char *argp;
326
327 argp = (unsigned char *)relstak();
328 while (alphanum(c) || (addc && c == addc)) {
329 GROWSTAKTOP();
330 pushstak(c);
331 c = readwc();
332 }
333 GROWSTAKTOP();
334 zerostak();
335 *argpp = argp; /* Return start offset against stakbot */
336 return (c);
337 }
338
339 #ifdef PROTOTYPES
340 static int
getch(unsigned char endch,int trimflag)341 getch(unsigned char endch, int trimflag)
342 #else
343 static int
344 getch(endch, trimflag)
345 unsigned char endch;
346 /*
347 * flag to check if an argument is going to be trimmed, here document
348 * output is never trimmed
349 */
350 int trimflag;
351 #endif
352 {
353 unsigned int d;
354 /*
355 * atflag to check if $@ has already been seen within double quotes
356 */
357 int atflag = 0;
358 retry:
359 d = readwc();
360 if (!subchar(d))
361 return (d);
362
363 if (d == DOLLAR) {
364 unsigned int c;
365
366 if ((c = readwc(), dolchar(c))) {
367 struct namnod *n = (struct namnod *)NIL;
368 int dolg = 0;
369 #ifdef DO_U_DOLAT_NOFAIL
370 int isg = 0;
371 #endif
372 #ifdef DO_SUBSTRING
373 int largest = 0;
374 #endif
375 int vsize = -1;
376 BOOL bra;
377 BOOL nulflg;
378 unsigned char *argp, *v = NULL;
379 unsigned char idb[2];
380 unsigned char *id = idb;
381 unsigned char oquote;
382
383 *id = '\0';
384
385 if ((bra = (c == BRACE)) != FALSE)
386 c = readwc();
387 #ifdef DO_SUBSTRING
388 getname:
389 #endif
390 if (letter(c)) { /* valid parameter name */
391
392 c = dolname(&argp, c, 0);
393 n = lookup(absstak(argp));
394 setstak(argp);
395 #ifndef DO_POSIX_UNSET
396 if (n->namflg & N_FUNCTN) {
397 error(badsub);
398 return (EOF);
399 }
400 #endif
401 #ifdef DO_LINENO
402 if (n == &linenonod) {
403 v = linenoval();
404 } else
405 #endif
406 v = n->namval;
407 id = (unsigned char *)n->namid;
408 peekc = c | MARK;
409 } else if (digchar(c)) { /* astchar or digits */
410 *id = c;
411 idb[1] = 0;
412 if (astchar(c)) { /* '*' or '@' */
413 if (c == '@' && !atflag && quote) {
414 quoted--;
415 atflag = 1;
416 }
417 #ifdef DO_U_DOLAT_NOFAIL
418 isg = dolg = 1;
419 #else
420 dolg = 1;
421 #endif
422 c = 1;
423 } else if (digit(c)) {
424 c -= '0';
425 #ifdef DO_POSIX_PARAM
426 if (bra) {
427 int dd;
428 int overflow = 0;
429 int maxmult = INT_MAX / 10;
430
431 while ((dd = readwc(),
432 digit(dd))) {
433 dd -= '0';
434 if (c > maxmult)
435 overflow = 1;
436 c *= 10;
437 if (INT_MAX - c < dd)
438 overflow = 1;
439 c += dd;
440 }
441 peekc = dd | MARK;
442 if (overflow)
443 c = INT_MAX;
444 }
445 #endif
446 }
447 /*
448 * Double cast is needed to work around a
449 * GCC bug.
450 */
451 v = ((c == 0) ?
452 cmdadr :
453 (dolc > 0 && c <= dolc) ?
454 dolv[c] :
455 (unsigned char *)(Intptr_t)(dolg = 0));
456 } else if (c == '$') {
457 v = pidadr;
458 } else if (c == '!') {
459 v = pcsadr;
460 } else if (c == '#') {
461 #ifdef DO_SUBSTRING
462 if (bra == 1) {
463 c = readwc();
464 if (c == ':' ||
465 c == '-' ||
466 c == '+' ||
467 c == '?' ||
468 c == '=') {
469 /*
470 * Check for corner case ${#?}
471 */
472 if (c == '?') {
473 int nc = readwc();
474
475 peekc = nc|MARK;
476 if (nc == '}') {
477 bra++;
478 goto getname;
479 }
480 }
481 itos(dolc);
482 v = numbuf;
483 goto docolon;
484 } else if (c != '}') {
485 bra++;
486 goto getname;
487 } else {
488 bra = 0;
489 }
490 }
491 #endif
492 itos(dolc);
493 v = numbuf;
494 } else if (c == '?') {
495 #ifdef DO_SIGNED_EXIT
496 sitos(retval);
497 #else
498 itos(retval);
499 #endif
500 v = numbuf;
501 #ifdef DO_DOL_SLASH
502 } else if (c == '/') {
503 if (retex.ex_code == CLD_EXITED) {
504 sitos(retex.ex_status);
505 v = numbuf;
506 } else if (retex.ex_code == C_NOEXEC ||
507 retex.ex_code == C_NOTFOUND) {
508 v = UC code2str(retex.ex_code);
509 } else {
510 sig2str(retex.ex_status,
511 (char *)numbuf);
512 v = numbuf;
513 }
514 #endif
515 } else if (c == '-') {
516 v = flagadr;
517 #ifdef DO_DOT_SH_PARAMS
518 } else if (bra && c == '.') {
519 unsigned char *shv;
520
521 c = dolname(&argp, c, '.');
522 v = absstak(argp); /* Variable name */
523 if (v[0] == '.' &&
524 v[1] == 's' &&
525 v[2] == 'h' &&
526 v[3] == '.' &&
527 (shv = shvar(&v[4])) != NULL) {
528 v = shv;
529 } else {
530 v = NULL;
531 }
532 setstak(argp);
533 peekc = c | MARK;
534 #endif
535 } else if (bra) {
536 error(badsub);
537 return (EOF);
538 } else {
539 goto retry;
540 }
541 c = readwc();
542 #ifdef DO_SUBSTRING
543 docolon:
544 #endif
545 if (c == ':' && bra == 1) { /* null and unset fix */
546 nulflg = 1;
547 c = readwc(); /* c now holds char past ':' */
548 } else {
549 nulflg = 0;
550 }
551 if (!defchar(c) && bra) { /* check "}=-+?#%" */
552 error(badsub);
553 return (EOF);
554 }
555 argp = 0;
556 if (bra) { /* ${...} */
557 /*
558 * This place is probably the wrong place to
559 * mark the word as expanded, but before, we
560 * did not mark a substitution to word in
561 * ${var-word} if "var" is unset.
562 */
563 macflag |= M_PARM;
564
565 if (c != '}') { /* word follows parameter */
566 /*
567 * Collect word or null string depending
568 * on parameter value and setchar(c).
569 */
570 argp = (unsigned char *)relstak();
571 if ((v == 0 ||
572 (nulflg && *v == 0)) ^
573 (setchar(c))) {
574 int ntrim = trimflag;
575
576 oquote = quote;
577 #ifdef DO_SUBSTRING
578 if (c == '#' || c == '%') {
579 unsigned int nc;
580
581 #ifdef __needed__
582 /*
583 * See globesc() below.
584 */
585 ntrim = 0;
586 #endif
587 nc = readwc();
588 if (nc == c) {
589 largest++;
590 } else {
591 peekc = nc|MARK;
592 }
593 quote = 0;
594 } else {
595 unsigned int nc;
596
597 nc = readwc();
598 if (nc == DQUOTE)
599 quote = 0;
600 peekc = nc|MARK;
601 }
602 #endif
603 copyto('}', ntrim);
604 quote = oquote;
605 } else {
606 skipto('}');
607 }
608 argp = absstak(argp);
609 }
610 } else {
611 peekc = c | MARK;
612 c = 0;
613 }
614 #ifdef DO_SUBSTRING
615 if (bra > 1) {
616 int l = 0;
617
618 if (c != '}' || argp) {
619 error(badsub);
620 return (EOF);
621 }
622 if (v)
623 l = mbschars(v);
624 itos(l);
625 v = numbuf;
626 }
627 if ((c == '#' || c == '%')) {
628 if (v) {
629 UIntptr_t b = relstakp(argp);
630
631 if (dolg) {
632 error(badsub);
633 return (EOF);
634 }
635 #ifdef __needed__
636 if (quote) {
637 /*
638 * This is a copy that we may
639 * shrink.
640 */
641 trim(argp);
642 }
643 #endif
644
645 /*
646 * Treat double quotes in glob pattern.
647 */
648 #ifdef __needed__
649 /*
650 * See ntrim = 0 above.
651 */
652 argp = globesc(argp);
653 #endif
654 if (c == '#') {
655 v = prefsubstr(v, argp,
656 largest);
657 } else {
658 vsize = suffsubstr(v, argp,
659 largest);
660 }
661 setstak(b);
662 } else {
663 /*
664 * Clear to let it fail later with
665 * an unset error with set -u.
666 */
667 argp = 0;
668 }
669 }
670 #endif
671 if (v && (!nulflg || *v)) {
672 /*
673 * Parameter is not unset and
674 * either non-null or the ':' is not present.
675 */
676
677 if (c != '+') {
678 Uchar sep = ' ';
679
680 #ifdef DO_IFS_SEP
681 if (ifsnod.namval)
682 sep = *ifsnod.namval;
683 #endif
684 /*
685 * Substitute parameter value
686 */
687 (void) mbtowc(NULL, NULL, 0);
688 for (;;) {
689 if (*v == 0 && quote) {
690 GROWSTAKTOP();
691 pushstak('\\');
692 GROWSTAKTOP();
693 pushstak('\0');
694 } else {
695 macflag |= M_PARM;
696 sizecpy(vsize, v,
697 trimflag);
698 }
699
700 if (dolg == 0 ||
701 (++dolg > dolc)) {
702 break;
703 } else {
704 /*
705 * $* and $@ expansion
706 */
707 v = dolv[dolg];
708 if (*id == '*' &&
709 quote) {
710 /*
711 * push quoted
712 * separator so
713 * that "$*"
714 * will not be
715 * broken into
716 * separate
717 * arguments.
718 */
719 if (!sep)
720 continue;
721 GROWSTAKTOP();
722 pushstak('\\');
723 GROWSTAKTOP();
724 pushstak(sep);
725 } else {
726 if (*id == '@')
727 macflag |=
728 M_DOLAT;
729 GROWSTAKTOP();
730 pushstak(' ');
731 }
732 }
733 }
734 }
735 } else if (argp) {
736 if (c == '?') {
737 if (trimflag)
738 trim(argp);
739 failed(id, *argp ? (const char *)argp :
740 badparam);
741 return (EOF);
742 } else if (c == '=') {
743 if (n) {
744 int slength = staktop - stakbot;
745 UIntptr_t aoff = argp - stakbot;
746 unsigned char *savp = fixstak();
747 struct ionod *iosav = iotemp;
748 unsigned char *newargp;
749
750 /*
751 * The malloc()-based stak.c
752 * will relocate the last item
753 * if we call fixstak();
754 */
755 argp = savp + aoff;
756
757 /*
758 * copy word onto stack, trim
759 * it, and then do assignment
760 */
761 usestak();
762 argp = trimcpy(argp, trimflag);
763 newargp = fixstak();
764 assign(n, newargp);
765 tdystak(savp, iosav);
766 (void) memcpystak(stakbot,
767 savp,
768 slength);
769 staktop = stakbot + slength;
770 } else {
771 error(badsub);
772 return (EOF);
773 }
774 }
775 #ifdef DO_U_DOLAT_NOFAIL
776 } else if ((flags & setflg) && isg == 0) {
777 #else
778 } else if (flags & setflg) {
779 #endif
780 failed(id, unset);
781 return (EOF);
782 }
783 goto retry;
784 #ifdef DO_DOL_PAREN
785 } else if (c == '(' && (macflag & M_NOCOMSUBST) == 0) {
786 comsubst(trimflag, COM_DOL_PAREN);
787 goto retry;
788 #endif
789 } else {
790 peekc = c | MARK;
791 }
792 } else if (d == endch) {
793 return (d);
794 } else if (d == SQUOTE) {
795 if (macflag & M_NOCOMSUBST)
796 return (d);
797 comsubst(trimflag, COM_BACKQUOTE);
798 goto retry;
799 } else if (d == DQUOTE && trimflag) {
800 if (!quote) {
801 atflag = 0;
802 quoted++;
803 }
804 quote ^= QUOTE;
805 goto retry;
806 }
807 return (d);
808 }
809
810 unsigned char *
macro(as)811 macro(as)
812 unsigned char *as;
813 {
814 macflag &= ~M_SPLIT;
815 (void) _macro(as);
816 return (fixstak());
817 }
818
819 unsigned char *
_macro(as)820 _macro(as)
821 unsigned char *as;
822 {
823 /*
824 * Strip "" and do $ substitution
825 * Leaves result on top of stack
826 */
827 BOOL savqu = quoted;
828 unsigned char savq = quote;
829 UIntptr_t b = relstak();
830 struct filehdr fb;
831
832 fb.fsiz = 1; /* It's a filehdr not a fileblk */
833 push((struct fileblk *)&fb);
834 estabf(as);
835 usestak();
836 quote = 0;
837 quoted = 0;
838 copyto(0, 1);
839 pop();
840 if (quoted && (stakbot == staktop)) {
841 GROWSTAKTOP();
842 pushstak('\\');
843 GROWSTAKTOP();
844 pushstak('\0');
845 zerostak();
846 /*
847 * above is the fix for *'.c' bug
848 */
849 }
850 quote = savq;
851 quoted = savqu;
852 return (absstak(b));
853 }
854 /* Save file descriptor for command substitution */
855 int savpipe = -1;
856
857 static void
comsubst(trimflag,type)858 comsubst(trimflag, type)
859 int trimflag;
860 int type;
861 /* trimflag - used to determine if argument will later be trimmed */
862 {
863 /*
864 * command substn
865 */
866 struct fileblk cb;
867 unsigned int d;
868 int strlngth = staktop - stakbot;
869 unsigned char *oldstaktop;
870 unsigned char *savptr = fixstak();
871 struct ionod *iosav = iotemp;
872 struct ionod *fiosav = fiotemp;
873 int oiof = 0;
874 int ofiof = 0;
875 unsigned char *pc;
876 struct trenod *tc = NULL;
877 int omacflag = macflag;
878
879 if (iosav) {
880 oiof = iosav->iofile;
881 iosav->iofile |= IOBARRIER;
882 }
883 if (fiosav) {
884 ofiof = fiosav->iofile;
885 fiosav->iofile |= IOBARRIER;
886 }
887
888 if (type == COM_BACKQUOTE) { /* `command` type command substitution */
889
890 usestak();
891 while ((d = readwc()) != SQUOTE && d) {
892 if (d == '\\') {
893 d = readwc();
894 if (!escchar(d) || (d == '"' && !quote)) {
895 /*
896 * trim quotes for `, \, or " if
897 * command substitution is within
898 * double quotes
899 */
900 GROWSTAKTOP();
901 pushstak('\\');
902 }
903 }
904 pc = readw(d);
905 /* d might be NULL */
906 if (*pc) {
907 while (*pc) {
908 GROWSTAKTOP();
909 pushstak(*pc++);
910 }
911 } else {
912 GROWSTAKTOP();
913 pushstak(*pc);
914 }
915 }
916 {
917 unsigned char *argc;
918
919 argc = fixstak();
920 push(&cb);
921 estabf(argc); /* read from string */
922 tc = cmd(EOFSYM, MTFLG | NLFLG | SEMIFLG);
923 }
924 }
925 #ifdef DO_DOL_PAREN
926 else { /* $(command) type command substitution */
927 d = readwc();
928 if (d == '(') { /* This is an arithmetic expression */
929 Intmax_t i;
930 unsigned char *argc;
931 struct argnod *arg = (struct argnod *)locstak();
932 unsigned char *argp = arg->argval;
933 int err;
934
935 /*
936 * savptr holds strlngth bytes in a saved area
937 * containing the already parsed part of the string.
938 * Use match_arith() to find the end of the expresssion
939 * and call macro() with this string to expand
940 * variables and embedded command substitutions.
941 * NOTE: match_arith() expects the string to be part
942 * of struct argnod, so argp must not start at stakbot.
943 */
944 *argp = '\0';
945 staktop = match_arith(argp);
946 arg = (struct argnod *)stakbot;
947 argc = staktop-1;
948 argp = arg->argval;
949 while (argc > argp && *(--argc) != ')')
950 ;
951 *argc = 0;
952 arg = (struct argnod *)fixstak();
953 argc = arg->argval;
954 argc = macro(&argc[2]);
955 (void) memcpystak(stakbot, savptr, strlngth);
956 staktop = stakbot + strlngth;
957 /*
958 * First implementation: just return the expanded string
959 */
960 i = strexpr(argc, &err);
961 if (err == 0) {
962 staktop = movstrstak(&numbuf[slltos(i)],
963 staktop);
964 } else {
965 exitval = err;
966 }
967 macflag = omacflag | M_ARITH;
968 if (iosav)
969 iosav->iofile = oiof;
970 if (fiosav)
971 fiosav->iofile = ofiof;
972 return;
973 }
974 peekc = d | MARK;
975 tc = cmd(')', MTFLG | NLFLG | SEMIFLG);
976 }
977 #endif
978 {
979 struct trenod *t;
980 int pv[2];
981 #ifdef DO_POSIX_E
982 int oret = retval;
983 struct excode oex;
984
985 oex = retex;
986 #endif
987
988 /*
989 * this is done like this so that the pipe
990 * is open only when needed
991 */
992 t = makefork(FPOU|STDOUT_FILENO, tc);
993 chkpipe(pv);
994 savpipe = pv[OTPIPE];
995 #ifdef DO_DOL_PAREN
996 if (type != COM_BACKQUOTE) {
997 push(&cb);
998 estabf(NULL);
999 }
1000 #endif
1001 initf(pv[INPIPE]); /* read from pipe */
1002 #ifdef PARSE_DEBUG
1003 prtree(t, "Command Substitution: ");
1004 #endif
1005 /*
1006 * The SVr4 version of the shell did not allocate a job
1007 * slot when XEC_NOSTOP was specified. Since we use vfork()
1008 * and optiomized pipes (-DDO_PIPE_PARENT) we also need to
1009 * specify XEC_ALLOCJOB to avoid that we overwrite the
1010 * existing job slot with command substitution.
1011 */
1012 execute(t, XEC_NOSTOP|XEC_ALLOCJOB, (int)(flags & errflg),
1013 no_pipe, pv);
1014 #ifdef DO_POSIX_E
1015 retval = oret; /* Restore old retval for $? */
1016 retex = oex;
1017 #endif
1018 close(pv[OTPIPE]);
1019 savpipe = -1;
1020 }
1021 #if 0
1022 /*
1023 * Do we really need to call this here?
1024 * execute() calls it already and if we leave this call here, we may
1025 * end up with accessing already free()d memory later.
1026 *
1027 * Calling tdystak() would free only the space that was allocated by
1028 * the parser (cmd()) and this seems to be of limited size. Given that
1029 * comsubst() is called as part of another command execution, it seems
1030 * that the lifetime of that space is not significantly enhanced.
1031 */
1032 tdystak(savptr, iosav);
1033 #endif
1034 (void) memcpystak(stakbot, savptr, strlngth);
1035 oldstaktop = staktop = stakbot + strlngth;
1036 while ((d = readwc()) != '\0') {
1037 if (quote || (d == '\\' && trimflag)) {
1038 unsigned char *rest;
1039 /*
1040 * quote output from command subst. if within double
1041 * quotes or backslash part of output
1042 */
1043 rest = readw(d);
1044 GROWSTAKTOP();
1045 pushstak('\\');
1046 while ((d = *rest++) != '\0') {
1047 /* Pick up all of multibyte character */
1048 GROWSTAKTOP();
1049 pushstak(d);
1050 }
1051 } else {
1052 pc = readw(d);
1053 while (*pc) {
1054 GROWSTAKTOP();
1055 pushstak(*pc++);
1056 }
1057 }
1058 }
1059 {
1060 extern pid_t parent;
1061 int rc;
1062 int ret = 0;
1063 int wstatus;
1064 int wcode;
1065
1066 while ((ret = wait_status(parent,
1067 &wcode, &wstatus,
1068 (WEXITED|WTRAPPED))) != parent) {
1069 /* break out if waitid(2) has failed */
1070 if (ret == -1)
1071 break;
1072 }
1073 rc = wstatus;
1074 if ((flags2 & fullexitcodeflg) == 0)
1075 rc &= 0xFF; /* As dumb as with historic wait */
1076 if (wcode == CLD_KILLED || wcode == CLD_DUMPED)
1077 rc |= SIGFLG;
1078 #ifdef DO_EXIT_MODFIX
1079 else if (wstatus != 0 && rc == 0)
1080 rc = SIGFLG; /* Use special value 128 */
1081 #endif
1082 #ifndef DO_POSIX_E
1083 if (rc && (flags & errflg))
1084 exitsh(rc);
1085 #endif
1086 exitval = rc;
1087 ex.ex_status = wstatus;
1088 ex.ex_code = wcode;
1089 ex.ex_pid = parent;
1090 flags |= eflag;
1091 #ifndef DO_POSIX_E
1092 exitset(); /* Set retval from exitval for $? */
1093 #endif
1094 }
1095 if (iosav)
1096 iosav->iofile = oiof;
1097 if (fiosav)
1098 fiosav->iofile = ofiof;
1099 while (oldstaktop != staktop) {
1100 /*
1101 * strip off trailing newlines from command substitution only
1102 */
1103 if ((*--staktop) != NL) {
1104 ++staktop;
1105 break;
1106 } else if (quote)
1107 staktop--; /* skip past backslashes if quoting */
1108 }
1109 pop();
1110
1111 macflag = omacflag | M_COMMAND;
1112 }
1113
1114 #define CPYSIZ 512
1115
1116 void
subst(in,ot)1117 subst(in, ot)
1118 int in;
1119 int ot;
1120 {
1121 unsigned int c;
1122 struct fileblk fb;
1123 int count = CPYSIZ;
1124 unsigned char *pc;
1125 #ifdef DO_POSIX_HERE
1126 int oquote = quote;
1127 #endif
1128
1129 push(&fb);
1130 initf(in);
1131 /*
1132 * DQUOTE used to stop it from quoting
1133 */
1134 #ifdef DO_POSIX_HERE
1135 quote = 0;
1136 #endif
1137 while ((c = (getch(DQUOTE, 0))) != '\0') {
1138 /*
1139 * read characters from here document and interpret them
1140 */
1141 if (c == '\\') {
1142 c = readwc();
1143 /*
1144 * check if character in here document is escaped
1145 */
1146 if (!escchar(c) || c == '"') {
1147 GROWSTAKTOP();
1148 pushstak('\\');
1149 }
1150 }
1151 pc = readw(c);
1152 /* c might be NULL */
1153 if (*pc) {
1154 while (*pc) {
1155 GROWSTAKTOP();
1156 pushstak(*pc++);
1157 }
1158 } else {
1159 GROWSTAKTOP();
1160 pushstak(*pc);
1161 }
1162 if (--count == 0) {
1163 flush(ot);
1164 count = CPYSIZ;
1165 }
1166 }
1167 #ifdef DO_POSIX_HERE
1168 quote = oquote;
1169 #endif
1170 flush(ot);
1171 pop();
1172 }
1173
1174 static void
flush(ot)1175 flush(ot)
1176 int ot;
1177 {
1178 write(ot, stakbot, staktop - stakbot);
1179 if (flags & execpr)
1180 write(output, stakbot, staktop - stakbot);
1181 staktop = stakbot;
1182 }
1183
1184 #ifdef DO_SUBSTRING
1185 static int
mbschars(v)1186 mbschars(v)
1187 unsigned char *v;
1188 {
1189 register unsigned char *s = v;
1190 wchar_t wc;
1191 int len;
1192 int chars = 0;
1193
1194 while (*s) {
1195 if ((len = mbtowc(&wc, (char *)s, MB_LEN_MAX)) <= 0) {
1196 (void) mbtowc(NULL, NULL, 0);
1197 len = 1;
1198 }
1199 s += len;
1200 chars++;
1201 }
1202 return (chars);
1203 }
1204
1205 /*
1206 * Prefix substring matcher for ${var#pat} and ${var##pat}
1207 *
1208 * Returns pointer to first non-matching character in the string.
1209 */
1210 static unsigned char *
prefsubstr(v,pat,largest)1211 prefsubstr(v, pat, largest)
1212 unsigned char *v; /* The data value to check */
1213 unsigned char *pat; /* The pattern to match against */
1214 int largest; /* Whether to match largest str */
1215 {
1216 register unsigned char *s = v;
1217 register unsigned char *r = v;
1218 register unsigned int c;
1219 wchar_t wc;
1220 int len;
1221
1222 do {
1223 c = *s;
1224 *s = '\0';
1225 if (gmatch(C v, C pat)) {
1226 if (!largest) {
1227 *s = c;
1228 return (s);
1229 }
1230 r = s;
1231 }
1232 *s = c;
1233
1234 if ((len = mbtowc(&wc, (char *)s, MB_LEN_MAX)) <= 0) {
1235 (void) mbtowc(NULL, NULL, 0);
1236 len = 1;
1237 }
1238 s += len;
1239 } while (c);
1240 return (r);
1241 }
1242
1243 /*
1244 * Return a pointer to the last multi byte character before "sp".
1245 * Currently always called after gmatch() and thus from an intact mbstate.
1246 */
1247 static unsigned char *
mbdecr(s,sp)1248 mbdecr(s, sp)
1249 unsigned char *s;
1250 unsigned char *sp;
1251 {
1252 wchar_t wc;
1253 int len;
1254
1255 while (s < sp) {
1256 if ((len = mbtowc(&wc, (char *)s, MB_LEN_MAX)) <= 0) {
1257 (void) mbtowc(NULL, NULL, 0);
1258 len = 1;
1259 }
1260 if ((s + len) >= sp)
1261 return (s);
1262 s += len;
1263 }
1264 return (sp-1);
1265 }
1266
1267 /*
1268 * Suffix substring matcher for ${var%pat} and ${var%%pat}
1269 *
1270 * Returns size of non-matching initial part in the string.
1271 */
1272 static int
suffsubstr(v,pat,largest)1273 suffsubstr(v, pat, largest)
1274 unsigned char *v; /* The data value to check */
1275 unsigned char *pat; /* The pattern to match against */
1276 int largest; /* Whether to match largest str */
1277 {
1278 register unsigned char *s = v;
1279 register int size = strlen(C v);
1280
1281 s += size;
1282 while (s >= v) {
1283 if (gmatch(C s, C pat)) {
1284 size = s - v;
1285 if (!largest)
1286 break;
1287 }
1288 s = mbdecr(v, s);
1289 }
1290 return (size);
1291 }
1292
1293 /*
1294 * Convert prefix and suffix pattern into something that is
1295 * accepted by glob().
1296 */
1297 #ifdef __needed__
1298 static Uchar *
globesc(argp)1299 globesc(argp)
1300 Uchar *argp;
1301 {
1302 int c;
1303 int escflag = FALSE;
1304 UIntptr_t b = relstak();
1305
1306 pushstak('\0'); /* Terminate current argp */
1307 (void) mbtowc(NULL, NULL, 0);
1308 while ((c = *argp) != '\0') {
1309 wchar_t wc;
1310 int len;
1311
1312 if ((len = mbtowc(&wc, C argp, MB_LEN_MAX)) <= 0) {
1313 (void) mbtowc(NULL, NULL, 0);
1314 len = 1;
1315 }
1316 if (c == '"') {
1317 escflag = !escflag;
1318 argp += len;
1319 continue;
1320 }
1321 if (escflag) {
1322 switch (c) {
1323
1324 case '\\':
1325 case '*':
1326 case '?':
1327 case '[':
1328 GROWSTAKTOP();
1329 pushstak('\\');
1330 break;
1331 default:
1332 ;
1333 }
1334 }
1335 while (len-- > 0) {
1336 GROWSTAKTOP();
1337 pushstak(*argp++);
1338 }
1339 }
1340 zerostak();
1341 staktop = (absstak(b));
1342 return (&staktop[1]); /* Point past first added null byte */
1343 }
1344 #endif
1345 #endif
1346
1347 /*
1348 * If vsize is >= 0, copy vsize characters, else copy all.
1349 * The mbstate is reset from our caller, thus we do not need to
1350 * call mbtowc(NULL, NULL, 0)
1351 */
1352 static void
sizecpy(vsize,v,trimflag)1353 sizecpy(vsize, v, trimflag)
1354 int vsize;
1355 Uchar *v;
1356 int trimflag;
1357 {
1358 int c;
1359
1360 while (vsize && (c = *v) != '\0') {
1361 wchar_t wc;
1362 int clength;
1363
1364 if ((clength = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0) {
1365 (void) mbtowc(NULL, NULL, 0);
1366 clength = 1;
1367 }
1368 if (quote || (c == '\\' && trimflag)) {
1369 GROWSTAKTOP();
1370 pushstak('\\');
1371 }
1372 while (clength-- > 0) {
1373 GROWSTAKTOP();
1374 pushstak(*v++);
1375 }
1376 if (vsize > 0)
1377 vsize--;
1378 }
1379 }
1380
1381 static Uchar *
trimcpy(argp,trimflag)1382 trimcpy(argp, trimflag)
1383 Uchar *argp;
1384 int trimflag;
1385 {
1386 int c;
1387
1388 (void) mbtowc(NULL, NULL, 0);
1389 while ((c = *argp) != '\0') {
1390 wchar_t wc;
1391 int len;
1392
1393 if ((len = mbtowc(&wc, C argp, MB_LEN_MAX)) <= 0) {
1394 (void) mbtowc(NULL, NULL, 0);
1395 len = 1;
1396 }
1397 if (c == '\\' && trimflag) {
1398 argp++;
1399 if (*argp == 0) {
1400 argp++;
1401 continue;
1402 }
1403 if ((len = mbtowc(&wc, C argp, MB_LEN_MAX)) <= 0) {
1404 (void) mbtowc(NULL, NULL, 0);
1405 len = 1;
1406 }
1407 }
1408 while (len-- > 0) {
1409 GROWSTAKTOP();
1410 pushstak(*argp++);
1411 }
1412 }
1413 return (argp);
1414 }
1415