sh: Save/restore changed variables in optimized command substitution.
[dragonfly.git] / bin / sh / expand.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
99512ac4
PA
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
984263bc
MD
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
1de703da
MD
37 *
38 * @(#)expand.c 8.5 (Berkeley) 5/15/95
32931063 39 * $FreeBSD: src/bin/sh/expand.c,v 1.89 2011/06/12 23:06:04 jilles Exp $
984263bc
MD
40 */
41
984263bc
MD
42#include <sys/types.h>
43#include <sys/time.h>
44#include <sys/stat.h>
984263bc 45#include <dirent.h>
99512ac4
PA
46#include <errno.h>
47#include <inttypes.h>
984263bc 48#include <limits.h>
99512ac4 49#include <pwd.h>
984263bc 50#include <stdio.h>
99512ac4 51#include <stdlib.h>
d13d0ee2 52#include <string.h>
99512ac4 53#include <unistd.h>
ead7935b 54#include <wchar.h>
984263bc
MD
55
56/*
57 * Routines to expand arguments to commands. We have to deal with
58 * backquotes, shell variables, and file metacharacters.
59 */
60
61#include "shell.h"
62#include "main.h"
63#include "nodes.h"
64#include "eval.h"
65#include "expand.h"
66#include "syntax.h"
67#include "parser.h"
68#include "jobs.h"
69#include "options.h"
70#include "var.h"
71#include "input.h"
72#include "output.h"
73#include "memalloc.h"
74#include "error.h"
75#include "mystring.h"
76#include "arith.h"
77#include "show.h"
78
79/*
80 * Structure specifying which parts of the string should be searched
81 * for IFS characters.
82 */
83
84struct ifsregion {
85 struct ifsregion *next; /* next region in list */
86 int begoff; /* offset of start of region */
87 int endoff; /* offset of end of region */
99512ac4 88 int inquotes; /* search for nul bytes only */
984263bc
MD
89};
90
91
99512ac4
PA
92static char *expdest; /* output of current string */
93static struct nodelist *argbackq; /* list of back quote expressions */
94static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
95static struct ifsregion *ifslastp; /* last struct in list */
96static struct arglist exparg; /* holds expanded arg list */
97
98static void argstr(char *, int);
99static char *exptilde(char *, int);
100static void expbackq(union node *, int, int);
101static int subevalvar(char *, char *, int, int, int, int, int);
102static char *evalvar(char *, int);
103static int varisset(char *, int);
104static void varvalue(char *, int, int, int);
105static void recordregion(int, int, int);
106static void removerecordregions(int);
107static void ifsbreakup(char *, struct arglist *);
108static void expandmeta(struct strlist *, int);
109static void expmeta(char *, char *);
110static void addfname(char *);
111static struct strlist *expsort(struct strlist *);
112static struct strlist *msort(struct strlist *, int);
113static char *cvtnum(int, char *);
ead7935b 114static int collate_range_cmp(wchar_t, wchar_t);
99512ac4
PA
115
116static int
ead7935b 117collate_range_cmp(wchar_t c1, wchar_t c2)
984263bc 118{
ead7935b 119 static wchar_t s1[2], s2[2];
984263bc 120
984263bc
MD
121 s1[0] = c1;
122 s2[0] = c2;
ead7935b 123 return (wcscoll(s1, s2));
984263bc
MD
124}
125
126/*
127 * Expand shell variables and backquotes inside a here document.
128 * union node *arg the document
129 * int fd; where to write the expanded version
130 */
131
132void
133expandhere(union node *arg, int fd)
134{
2038fb68 135 expandarg(arg, NULL, 0);
984263bc
MD
136 xwrite(fd, stackblock(), expdest - stackblock());
137}
138
99512ac4
PA
139static char *
140stputs_quotes(const char *data, const char *syntax, char *p)
141{
142 while (*data) {
143 CHECKSTRSPACE(2, p);
144 if (syntax[(int)*data] == CCTL)
145 USTPUTC(CTLESC, p);
146 USTPUTC(*data++, p);
147 }
148 return (p);
149}
150#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
984263bc
MD
151
152/*
99512ac4
PA
153 * Perform expansions on an argument, placing the resulting list of arguments
154 * in arglist. Parameter expansion, command substitution and arithmetic
155 * expansion are always performed; additional expansions can be requested
156 * via flag (EXP_*).
157 * The result is left in the stack string.
158 * When arglist is NULL, perform here document expansion.
159 *
160 * Caution: this function uses global state and is not reentrant.
161 * However, a new invocation after an interrupted invocation is safe
162 * and will reset the global state for the new call.
984263bc 163 */
984263bc
MD
164void
165expandarg(union node *arg, struct arglist *arglist, int flag)
166{
167 struct strlist *sp;
168 char *p;
169
170 argbackq = arg->narg.backquote;
171 STARTSTACKSTR(expdest);
172 ifsfirst.next = NULL;
173 ifslastp = NULL;
174 argstr(arg->narg.text, flag);
175 if (arglist == NULL) {
97fe2313 176 STACKSTRNUL(expdest);
984263bc
MD
177 return; /* here document expanded */
178 }
179 STPUTC('\0', expdest);
180 p = grabstackstr(expdest);
181 exparg.lastp = &exparg.list;
182 /*
183 * TODO - EXP_REDIR
184 */
185 if (flag & EXP_FULL) {
186 ifsbreakup(p, &exparg);
187 *exparg.lastp = NULL;
188 exparg.lastp = &exparg.list;
189 expandmeta(exparg.list, flag);
190 } else {
191 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
192 rmescapes(p);
193 sp = (struct strlist *)stalloc(sizeof (struct strlist));
194 sp->text = p;
195 *exparg.lastp = sp;
196 exparg.lastp = &sp->next;
197 }
198 while (ifsfirst.next != NULL) {
199 struct ifsregion *ifsp;
200 INTOFF;
201 ifsp = ifsfirst.next->next;
202 ckfree(ifsfirst.next);
203 ifsfirst.next = ifsp;
204 INTON;
205 }
206 *exparg.lastp = NULL;
207 if (exparg.list) {
208 *arglist->lastp = exparg.list;
209 arglist->lastp = exparg.lastp;
210 }
211}
212
213
214
215/*
99512ac4
PA
216 * Perform parameter expansion, command substitution and arithmetic
217 * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
218 * Processing ends at a CTLENDVAR character as well as '\0'.
219 * This is used to expand word in ${var+word} etc.
220 * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
221 * characters to allow for further processing.
222 * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
984263bc 223 */
99512ac4 224static void
984263bc
MD
225argstr(char *p, int flag)
226{
227 char c;
228 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
229 int firsteq = 1;
99512ac4
PA
230 int split_lit;
231 int lit_quoted;
984263bc 232
99512ac4
PA
233 split_lit = flag & EXP_SPLIT_LIT;
234 lit_quoted = flag & EXP_LIT_QUOTED;
235 flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
984263bc
MD
236 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
237 p = exptilde(p, flag);
238 for (;;) {
99512ac4 239 CHECKSTRSPACE(2, expdest);
984263bc
MD
240 switch (c = *p++) {
241 case '\0':
99512ac4 242 case CTLENDVAR:
984263bc
MD
243 goto breakloop;
244 case CTLQUOTEMARK:
99512ac4 245 lit_quoted = 1;
984263bc
MD
246 /* "$@" syntax adherence hack */
247 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
248 break;
249 if ((flag & EXP_FULL) != 0)
99512ac4
PA
250 USTPUTC(c, expdest);
251 break;
252 case CTLQUOTEEND:
253 lit_quoted = 0;
984263bc
MD
254 break;
255 case CTLESC:
256 if (quotes)
99512ac4 257 USTPUTC(c, expdest);
984263bc 258 c = *p++;
99512ac4
PA
259 USTPUTC(c, expdest);
260 if (split_lit && !lit_quoted)
261 recordregion(expdest - stackblock() -
262 (quotes ? 2 : 1),
263 expdest - stackblock(), 0);
984263bc
MD
264 break;
265 case CTLVAR:
266 p = evalvar(p, flag);
267 break;
268 case CTLBACKQ:
269 case CTLBACKQ|CTLQUOTE:
270 expbackq(argbackq->n, c & CTLQUOTE, flag);
271 argbackq = argbackq->next;
272 break;
273 case CTLENDARI:
274 expari(flag);
275 break;
276 case ':':
277 case '=':
278 /*
279 * sort of a hack - expand tildes in variable
280 * assignments (after the first '=' and after ':'s).
281 */
99512ac4
PA
282 USTPUTC(c, expdest);
283 if (split_lit && !lit_quoted)
284 recordregion(expdest - stackblock() - 1,
285 expdest - stackblock(), 0);
286 if (flag & EXP_VARTILDE && *p == '~' &&
287 (c != '=' || firsteq)) {
288 if (c == '=')
289 firsteq = 0;
984263bc
MD
290 p = exptilde(p, flag);
291 }
292 break;
293 default:
99512ac4
PA
294 USTPUTC(c, expdest);
295 if (split_lit && !lit_quoted)
296 recordregion(expdest - stackblock() - 1,
297 expdest - stackblock(), 0);
984263bc
MD
298 }
299 }
300breakloop:;
301}
302
99512ac4
PA
303/*
304 * Perform tilde expansion, placing the result in the stack string and
305 * returning the next position in the input string to process.
306 */
307static char *
984263bc
MD
308exptilde(char *p, int flag)
309{
310 char c, *startp = p;
311 struct passwd *pw;
312 char *home;
313 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
314
315 while ((c = *p) != '\0') {
316 switch(c) {
99512ac4
PA
317 case CTLESC: /* This means CTL* are always considered quoted. */
318 case CTLVAR:
319 case CTLBACKQ:
320 case CTLBACKQ | CTLQUOTE:
321 case CTLARI:
322 case CTLENDARI:
984263bc
MD
323 case CTLQUOTEMARK:
324 return (startp);
325 case ':':
326 if (flag & EXP_VARTILDE)
327 goto done;
328 break;
329 case '/':
99512ac4 330 case CTLENDVAR:
984263bc
MD
331 goto done;
332 }
333 p++;
334 }
335done:
336 *p = '\0';
337 if (*(startp+1) == '\0') {
338 if ((home = lookupvar("HOME")) == NULL)
339 goto lose;
340 } else {
341 if ((pw = getpwnam(startp+1)) == NULL)
342 goto lose;
343 home = pw->pw_dir;
344 }
345 if (*home == '\0')
346 goto lose;
347 *p = c;
99512ac4
PA
348 if (quotes)
349 STPUTS_QUOTES(home, SQSYNTAX, expdest);
350 else
351 STPUTS(home, expdest);
984263bc
MD
352 return (p);
353lose:
354 *p = c;
355 return (startp);
356}
357
358
99512ac4 359static void
984263bc
MD
360removerecordregions(int endoff)
361{
362 if (ifslastp == NULL)
363 return;
364
365 if (ifsfirst.endoff > endoff) {
366 while (ifsfirst.next != NULL) {
367 struct ifsregion *ifsp;
368 INTOFF;
369 ifsp = ifsfirst.next->next;
370 ckfree(ifsfirst.next);
371 ifsfirst.next = ifsp;
372 INTON;
373 }
374 if (ifsfirst.begoff > endoff)
375 ifslastp = NULL;
376 else {
377 ifslastp = &ifsfirst;
378 ifsfirst.endoff = endoff;
379 }
380 return;
381 }
af260b21 382
984263bc
MD
383 ifslastp = &ifsfirst;
384 while (ifslastp->next && ifslastp->next->begoff < endoff)
385 ifslastp=ifslastp->next;
386 while (ifslastp->next != NULL) {
387 struct ifsregion *ifsp;
388 INTOFF;
389 ifsp = ifslastp->next->next;
390 ckfree(ifslastp->next);
391 ifslastp->next = ifsp;
392 INTON;
393 }
394 if (ifslastp->endoff > endoff)
395 ifslastp->endoff = endoff;
396}
397
398/*
399 * Expand arithmetic expression. Backup to start of expression,
400 * evaluate, place result in (backed up) result, adjust string position.
401 */
402void
403expari(int flag)
404{
99512ac4
PA
405 char *p, *q, *start;
406 arith_t result;
984263bc
MD
407 int begoff;
408 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
409 int quoted;
410
984263bc
MD
411 /*
412 * This routine is slightly over-complicated for
413 * efficiency. First we make sure there is
414 * enough space for the result, which may be bigger
99512ac4 415 * than the expression. Next we
984263bc
MD
416 * scan backwards looking for the start of arithmetic. If the
417 * next previous character is a CTLESC character, then we
418 * have to rescan starting from the beginning since CTLESC
419 * characters have to be processed left to right.
420 */
99512ac4 421 CHECKSTRSPACE(DIGITS(result) - 2, expdest);
984263bc
MD
422 USTPUTC('\0', expdest);
423 start = stackblock();
424 p = expdest - 2;
425 while (p >= start && *p != CTLARI)
426 --p;
427 if (p < start || *p != CTLARI)
428 error("missing CTLARI (shouldn't happen)");
429 if (p > start && *(p - 1) == CTLESC)
430 for (p = start; *p != CTLARI; p++)
431 if (*p == CTLESC)
432 p++;
433
434 if (p[1] == '"')
435 quoted=1;
436 else
437 quoted=0;
438 begoff = p - start;
439 removerecordregions(begoff);
440 if (quotes)
441 rmescapes(p+2);
99512ac4 442 q = grabstackstr(expdest);
984263bc 443 result = arith(p+2);
99512ac4
PA
444 ungrabstackstr(q, expdest);
445 fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
984263bc
MD
446 while (*p++)
447 ;
448 if (quoted == 0)
449 recordregion(begoff, p - 1 - start, 0);
450 result = expdest - p + 1;
451 STADJUST(-result, expdest);
452}
453
454
455/*
99512ac4 456 * Perform command substitution.
984263bc 457 */
99512ac4 458static void
984263bc
MD
459expbackq(union node *cmd, int quoted, int flag)
460{
461 struct backcmd in;
462 int i;
463 char buf[128];
464 char *p;
465 char *dest = expdest;
466 struct ifsregion saveifs, *savelastp;
467 struct nodelist *saveargbackq;
468 char lastc;
469 int startloc = dest - stackblock();
470 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
984263bc 471 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
5b762f1a 472 int nnl;
984263bc
MD
473
474 INTOFF;
475 saveifs = ifsfirst;
476 savelastp = ifslastp;
477 saveargbackq = argbackq;
984263bc
MD
478 p = grabstackstr(dest);
479 evalbackcmd(cmd, &in);
480 ungrabstackstr(p, dest);
481 ifsfirst = saveifs;
482 ifslastp = savelastp;
483 argbackq = saveargbackq;
984263bc
MD
484
485 p = in.buf;
486 lastc = '\0';
5b762f1a
SS
487 nnl = 0;
488 /* Don't copy trailing newlines */
984263bc
MD
489 for (;;) {
490 if (--in.nleft < 0) {
491 if (in.fd < 0)
492 break;
493 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
494 TRACE(("expbackq: read returns %d\n", i));
495 if (i <= 0)
496 break;
497 p = buf;
498 in.nleft = i - 1;
499 }
500 lastc = *p++;
501 if (lastc != '\0') {
5b762f1a
SS
502 if (lastc == '\n') {
503 nnl++;
504 } else {
99512ac4 505 CHECKSTRSPACE(nnl + 2, dest);
5b762f1a
SS
506 while (nnl > 0) {
507 nnl--;
99512ac4 508 USTPUTC('\n', dest);
5b762f1a 509 }
99512ac4
PA
510 if (quotes && syntax[(int)lastc] == CCTL)
511 USTPUTC(CTLESC, dest);
512 USTPUTC(lastc, dest);
5b762f1a 513 }
984263bc
MD
514 }
515 }
516
984263bc
MD
517 if (in.fd >= 0)
518 close(in.fd);
519 if (in.buf)
520 ckfree(in.buf);
521 if (in.jp)
2038fb68 522 exitstatus = waitforjob(in.jp, NULL);
984263bc
MD
523 if (quoted == 0)
524 recordregion(startloc, dest - stackblock(), 0);
99512ac4
PA
525 TRACE(("expbackq: size=%td: \"%.*s\"\n",
526 ((dest - stackblock()) - startloc),
527 (int)((dest - stackblock()) - startloc),
984263bc
MD
528 stackblock() + startloc));
529 expdest = dest;
530 INTON;
531}
532
533
534
99512ac4 535static int
984263bc 536subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
99512ac4 537 int varflags, int quotes)
984263bc
MD
538{
539 char *startp;
540 char *loc = NULL;
541 char *q;
542 int c = 0;
984263bc
MD
543 struct nodelist *saveargbackq = argbackq;
544 int amount;
545
99512ac4
PA
546 argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
547 subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
548 EXP_CASE : 0) | EXP_TILDE);
984263bc 549 STACKSTRNUL(expdest);
984263bc
MD
550 argbackq = saveargbackq;
551 startp = stackblock() + startloc;
552 if (str == NULL)
553 str = stackblock() + strloc;
554
555 switch (subtype) {
556 case VSASSIGN:
557 setvar(str, startp, 0);
558 amount = startp - expdest;
559 STADJUST(amount, expdest);
560 varflags &= ~VSNUL;
984263bc
MD
561 return 1;
562
563 case VSQUESTION:
564 if (*p != CTLENDVAR) {
99512ac4 565 outfmt(out2, "%s\n", startp);
2038fb68 566 error(NULL);
984263bc 567 }
af260b21 568 error("%.*s: parameter %snot set", (int)(p - str - 1),
984263bc
MD
569 str, (varflags & VSNUL) ? "null or "
570 : nullstr);
571 return 0;
572
573 case VSTRIMLEFT:
574 for (loc = startp; loc < str; loc++) {
575 c = *loc;
576 *loc = '\0';
99512ac4 577 if (patmatch(str, startp, quotes)) {
984263bc
MD
578 *loc = c;
579 goto recordleft;
580 }
581 *loc = c;
99512ac4 582 if (quotes && *loc == CTLESC)
984263bc
MD
583 loc++;
584 }
585 return 0;
586
587 case VSTRIMLEFTMAX:
588 for (loc = str - 1; loc >= startp;) {
589 c = *loc;
590 *loc = '\0';
99512ac4 591 if (patmatch(str, startp, quotes)) {
984263bc
MD
592 *loc = c;
593 goto recordleft;
594 }
595 *loc = c;
596 loc--;
99512ac4 597 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
984263bc
MD
598 for (q = startp; q < loc; q++)
599 if (*q == CTLESC)
600 q++;
601 if (q > loc)
602 loc--;
603 }
604 }
605 return 0;
606
607 case VSTRIMRIGHT:
608 for (loc = str - 1; loc >= startp;) {
99512ac4 609 if (patmatch(str, loc, quotes)) {
984263bc
MD
610 amount = loc - expdest;
611 STADJUST(amount, expdest);
612 return 1;
613 }
614 loc--;
99512ac4 615 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
984263bc
MD
616 for (q = startp; q < loc; q++)
617 if (*q == CTLESC)
618 q++;
619 if (q > loc)
620 loc--;
621 }
622 }
623 return 0;
624
625 case VSTRIMRIGHTMAX:
626 for (loc = startp; loc < str - 1; loc++) {
99512ac4 627 if (patmatch(str, loc, quotes)) {
984263bc
MD
628 amount = loc - expdest;
629 STADJUST(amount, expdest);
630 return 1;
631 }
99512ac4 632 if (quotes && *loc == CTLESC)
984263bc
MD
633 loc++;
634 }
635 return 0;
636
637
638 default:
639 abort();
640 }
641
642recordleft:
643 amount = ((str - 1) - (loc - startp)) - expdest;
644 STADJUST(amount, expdest);
645 while (loc != str - 1)
646 *startp++ = *loc++;
647 return 1;
648}
649
650
651/*
652 * Expand a variable, and return a pointer to the next character in the
653 * input string.
654 */
655
99512ac4 656static char *
984263bc
MD
657evalvar(char *p, int flag)
658{
659 int subtype;
660 int varflags;
661 char *var;
662 char *val;
663 int patloc;
664 int c;
665 int set;
666 int special;
667 int startloc;
668 int varlen;
fd296645 669 int varlenb;
984263bc
MD
670 int easy;
671 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
672
af260b21 673 varflags = (unsigned char)*p++;
984263bc
MD
674 subtype = varflags & VSTYPE;
675 var = p;
676 special = 0;
677 if (! is_name(*p))
678 special = 1;
679 p = strchr(p, '=') + 1;
680again: /* jump here after setting a variable with ${var=text} */
e0752c76
SK
681 if (varflags & VSLINENO) {
682 set = 1;
683 special = 0;
684 val = var;
685 p[-1] = '\0'; /* temporarily overwrite '=' to have \0
686 terminated string */
687 } else if (special) {
984263bc
MD
688 set = varisset(var, varflags & VSNUL);
689 val = NULL;
690 } else {
691 val = bltinlookup(var, 1);
692 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
693 val = NULL;
694 set = 0;
695 } else
696 set = 1;
697 }
698 varlen = 0;
699 startloc = expdest - stackblock();
99512ac4 700 if (!set && uflag && *var != '@' && *var != '*') {
984263bc
MD
701 switch (subtype) {
702 case VSNORMAL:
703 case VSTRIMLEFT:
704 case VSTRIMLEFTMAX:
705 case VSTRIMRIGHT:
706 case VSTRIMRIGHTMAX:
707 case VSLENGTH:
af260b21
PA
708 error("%.*s: parameter not set", (int)(p - var - 1),
709 var);
984263bc
MD
710 }
711 }
712 if (set && subtype != VSPLUS) {
713 /* insert the value of the variable */
714 if (special) {
af260b21 715 varvalue(var, varflags & VSQUOTE, subtype, flag);
984263bc 716 if (subtype == VSLENGTH) {
fd296645
PA
717 varlenb = expdest - stackblock() - startloc;
718 varlen = varlenb;
719 if (localeisutf8) {
720 val = stackblock() + startloc;
721 for (;val != expdest; val++)
722 if ((*val & 0xC0) == 0x80)
723 varlen--;
724 }
725 STADJUST(-varlenb, expdest);
984263bc
MD
726 }
727 } else {
728 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
729 : BASESYNTAX;
730
731 if (subtype == VSLENGTH) {
732 for (;*val; val++)
fd296645
PA
733 if (!localeisutf8 ||
734 (*val & 0xC0) != 0x80)
735 varlen++;
984263bc
MD
736 }
737 else {
99512ac4
PA
738 if (quotes)
739 STPUTS_QUOTES(val, syntax, expdest);
740 else
741 STPUTS(val, expdest);
984263bc
MD
742
743 }
744 }
745 }
746
747 if (subtype == VSPLUS)
748 set = ! set;
749
750 easy = ((varflags & VSQUOTE) == 0 ||
751 (*var == '@' && shellparam.nparam != 1));
752
753
754 switch (subtype) {
755 case VSLENGTH:
756 expdest = cvtnum(varlen, expdest);
757 goto record;
758
759 case VSNORMAL:
760 if (!easy)
761 break;
762record:
763 recordregion(startloc, expdest - stackblock(),
5b14c76d
PA
764 varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
765 (*var == '@' || *var == '*')));
984263bc
MD
766 break;
767
768 case VSPLUS:
769 case VSMINUS:
770 if (!set) {
99512ac4
PA
771 argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
772 (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
984263bc
MD
773 break;
774 }
775 if (easy)
776 goto record;
777 break;
778
779 case VSTRIMLEFT:
780 case VSTRIMLEFTMAX:
781 case VSTRIMRIGHT:
782 case VSTRIMRIGHTMAX:
783 if (!set)
784 break;
785 /*
786 * Terminate the string and start recording the pattern
787 * right after it
788 */
789 STPUTC('\0', expdest);
790 patloc = expdest - stackblock();
791 if (subevalvar(p, NULL, patloc, subtype,
99512ac4 792 startloc, varflags, quotes) == 0) {
984263bc
MD
793 int amount = (expdest - stackblock() - patloc) + 1;
794 STADJUST(-amount, expdest);
795 }
796 /* Remove any recorded regions beyond start of variable */
797 removerecordregions(startloc);
798 goto record;
799
800 case VSASSIGN:
801 case VSQUESTION:
802 if (!set) {
99512ac4
PA
803 if (subevalvar(p, var, 0, subtype, startloc, varflags,
804 quotes)) {
984263bc 805 varflags &= ~VSNUL;
af260b21
PA
806 /*
807 * Remove any recorded regions beyond
808 * start of variable
984263bc
MD
809 */
810 removerecordregions(startloc);
811 goto again;
812 }
813 break;
814 }
815 if (easy)
816 goto record;
817 break;
818
af260b21
PA
819 case VSERROR:
820 c = p - var - 1;
821 error("${%.*s%s}: Bad substitution", c, var,
822 (c > 0 && *p != CTLENDVAR) ? "..." : "");
823
984263bc
MD
824 default:
825 abort();
826 }
e0752c76 827 p[-1] = '='; /* recover overwritten '=' */
984263bc
MD
828
829 if (subtype != VSNORMAL) { /* skip to end of alternative */
830 int nesting = 1;
831 for (;;) {
832 if ((c = *p++) == CTLESC)
833 p++;
834 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
835 if (set)
836 argbackq = argbackq->next;
837 } else if (c == CTLVAR) {
838 if ((*p++ & VSTYPE) != VSNORMAL)
839 nesting++;
840 } else if (c == CTLENDVAR) {
841 if (--nesting == 0)
842 break;
843 }
844 }
845 }
846 return p;
847}
848
849
850
851/*
852 * Test whether a specialized variable is set.
853 */
854
99512ac4 855static int
984263bc
MD
856varisset(char *name, int nulok)
857{
858
859 if (*name == '!')
99512ac4 860 return backgndpidset();
984263bc
MD
861 else if (*name == '@' || *name == '*') {
862 if (*shellparam.p == NULL)
863 return 0;
864
865 if (nulok) {
866 char **av;
867
868 for (av = shellparam.p; *av; av++)
869 if (**av != '\0')
870 return 1;
871 return 0;
872 }
873 } else if (is_digit(*name)) {
874 char *ap;
875 int num = atoi(name);
876
877 if (num > shellparam.nparam)
878 return 0;
879
880 if (num == 0)
881 ap = arg0;
882 else
883 ap = shellparam.p[num - 1];
884
885 if (nulok && (ap == NULL || *ap == '\0'))
886 return 0;
887 }
888 return 1;
889}
890
99512ac4
PA
891static void
892strtodest(const char *p, int flag, int subtype, int quoted)
893{
894 if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH)
895 STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
896 else
897 STPUTS(p, expdest);
898}
984263bc
MD
899
900/*
901 * Add the value of a specialized variable to the stack string.
902 */
903
99512ac4 904static void
af260b21 905varvalue(char *name, int quoted, int subtype, int flag)
984263bc
MD
906{
907 int num;
908 char *p;
909 int i;
984263bc
MD
910 char sep;
911 char **ap;
984263bc
MD
912
913 switch (*name) {
914 case '$':
915 num = rootpid;
916 goto numvar;
917 case '?':
918 num = oexitstatus;
919 goto numvar;
920 case '#':
921 num = shellparam.nparam;
922 goto numvar;
923 case '!':
99512ac4 924 num = backgndpidval();
984263bc
MD
925numvar:
926 expdest = cvtnum(num, expdest);
927 break;
928 case '-':
929 for (i = 0 ; i < NOPTS ; i++) {
930 if (optlist[i].val)
931 STPUTC(optlist[i].letter, expdest);
932 }
933 break;
934 case '@':
af260b21 935 if (flag & EXP_FULL && quoted) {
984263bc 936 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
99512ac4 937 strtodest(p, flag, subtype, quoted);
984263bc
MD
938 if (*ap)
939 STPUTC('\0', expdest);
940 }
941 break;
942 }
af260b21 943 /* FALLTHROUGH */
984263bc 944 case '*':
af260b21 945 if (ifsset())
984263bc
MD
946 sep = ifsval()[0];
947 else
948 sep = ' ';
949 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
99512ac4 950 strtodest(p, flag, subtype, quoted);
5b14c76d
PA
951 if (!*ap)
952 break;
953 if (sep || (flag & EXP_FULL && !quoted && **ap != '\0'))
984263bc
MD
954 STPUTC(sep, expdest);
955 }
956 break;
957 case '0':
958 p = arg0;
99512ac4 959 strtodest(p, flag, subtype, quoted);
984263bc
MD
960 break;
961 default:
962 if (is_digit(*name)) {
963 num = atoi(name);
964 if (num > 0 && num <= shellparam.nparam) {
965 p = shellparam.p[num - 1];
99512ac4 966 strtodest(p, flag, subtype, quoted);
984263bc
MD
967 }
968 }
969 break;
970 }
971}
972
973
974
975/*
404d2224 976 * Record the fact that we have to scan this region of the
984263bc
MD
977 * string for IFS characters.
978 */
979
99512ac4
PA
980static void
981recordregion(int start, int end, int inquotes)
984263bc
MD
982{
983 struct ifsregion *ifsp;
984
985 if (ifslastp == NULL) {
986 ifsp = &ifsfirst;
987 } else {
99512ac4
PA
988 if (ifslastp->endoff == start
989 && ifslastp->inquotes == inquotes) {
990 /* extend previous area */
991 ifslastp->endoff = end;
992 return;
993 }
984263bc
MD
994 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
995 ifslastp->next = ifsp;
996 }
997 ifslastp = ifsp;
998 ifslastp->next = NULL;
999 ifslastp->begoff = start;
1000 ifslastp->endoff = end;
99512ac4 1001 ifslastp->inquotes = inquotes;
984263bc
MD
1002}
1003
1004
1005
1006/*
1007 * Break the argument string into pieces based upon IFS and add the
1008 * strings to the argument list. The regions of the string to be
1009 * searched for IFS characters have been stored by recordregion.
99512ac4
PA
1010 * CTLESC characters are preserved but have little effect in this pass
1011 * other than escaping CTL* characters. In particular, they do not escape
1012 * IFS characters: that should be done with the ifsregion mechanism.
1013 * CTLQUOTEMARK characters are used to preserve empty quoted strings.
1014 * This pass treats them as a regular character, making the string non-empty.
1015 * Later, they are removed along with the other CTL* characters.
984263bc 1016 */
99512ac4 1017static void
984263bc
MD
1018ifsbreakup(char *string, struct arglist *arglist)
1019{
1020 struct ifsregion *ifsp;
1021 struct strlist *sp;
1022 char *start;
1023 char *p;
1024 char *q;
492efe05 1025 const char *ifs;
99512ac4
PA
1026 const char *ifsspc;
1027 int had_param_ch = 0;
984263bc
MD
1028
1029 start = string;
99512ac4
PA
1030
1031 if (ifslastp == NULL) {
1032 /* Return entire argument, IFS doesn't apply to any of it */
1033 sp = (struct strlist *)stalloc(sizeof *sp);
1034 sp->text = start;
1035 *arglist->lastp = sp;
1036 arglist->lastp = &sp->next;
1037 return;
1038 }
1039
1040 ifs = ifsset() ? ifsval() : " \t\n";
1041
1042 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1043 p = string + ifsp->begoff;
1044 while (p < string + ifsp->endoff) {
1045 q = p;
1046 if (*p == CTLESC)
1047 p++;
1048 if (ifsp->inquotes) {
1049 /* Only NULs (should be from "$@") end args */
1050 had_param_ch = 1;
1051 if (*p != 0) {
984263bc 1052 p++;
99512ac4
PA
1053 continue;
1054 }
1055 ifsspc = NULL;
1056 } else {
1057 if (!strchr(ifs, *p)) {
1058 had_param_ch = 1;
984263bc 1059 p++;
99512ac4
PA
1060 continue;
1061 }
1062 ifsspc = strchr(" \t\n", *p);
1063
1064 /* Ignore IFS whitespace at start */
1065 if (q == start && ifsspc != NULL) {
984263bc 1066 p++;
99512ac4
PA
1067 start = p;
1068 continue;
1069 }
1070 had_param_ch = 0;
984263bc 1071 }
99512ac4
PA
1072
1073 /* Save this argument... */
1074 *q = '\0';
984263bc
MD
1075 sp = (struct strlist *)stalloc(sizeof *sp);
1076 sp->text = start;
1077 *arglist->lastp = sp;
1078 arglist->lastp = &sp->next;
99512ac4
PA
1079 p++;
1080
1081 if (ifsspc != NULL) {
1082 /* Ignore further trailing IFS whitespace */
1083 for (; p < string + ifsp->endoff; p++) {
1084 q = p;
1085 if (*p == CTLESC)
1086 p++;
1087 if (strchr(ifs, *p) == NULL) {
1088 p = q;
1089 break;
1090 }
1091 if (strchr(" \t\n", *p) == NULL) {
1092 p++;
1093 break;
1094 }
1095 }
1096 }
1097 start = p;
984263bc 1098 }
99512ac4
PA
1099 }
1100
1101 /*
1102 * Save anything left as an argument.
1103 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1104 * generating 2 arguments, the second of which is empty.
1105 * Some recent clarification of the Posix spec say that it
1106 * should only generate one....
1107 */
1108 if (had_param_ch || *start != 0) {
984263bc
MD
1109 sp = (struct strlist *)stalloc(sizeof *sp);
1110 sp->text = start;
1111 *arglist->lastp = sp;
1112 arglist->lastp = &sp->next;
1113 }
1114}
1115
1116
99512ac4
PA
1117static char expdir[PATH_MAX];
1118#define expdir_end (expdir + sizeof(expdir))
984263bc
MD
1119
1120/*
99512ac4
PA
1121 * Perform pathname generation and remove control characters.
1122 * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1123 * The results are stored in the list exparg.
984263bc 1124 */
99512ac4 1125static void
984263bc
MD
1126expandmeta(struct strlist *str, int flag __unused)
1127{
1128 char *p;
1129 struct strlist **savelastp;
1130 struct strlist *sp;
1131 char c;
1132 /* TODO - EXP_REDIR */
1133
1134 while (str) {
1135 if (fflag)
1136 goto nometa;
1137 p = str->text;
1138 for (;;) { /* fast check for meta chars */
1139 if ((c = *p++) == '\0')
1140 goto nometa;
99512ac4 1141 if (c == '*' || c == '?' || c == '[')
984263bc
MD
1142 break;
1143 }
1144 savelastp = exparg.lastp;
1145 INTOFF;
984263bc 1146 expmeta(expdir, str->text);
984263bc
MD
1147 INTON;
1148 if (exparg.lastp == savelastp) {
1149 /*
1150 * no matches
1151 */
1152nometa:
1153 *exparg.lastp = str;
1154 rmescapes(str->text);
1155 exparg.lastp = &str->next;
1156 } else {
1157 *exparg.lastp = NULL;
1158 *savelastp = sp = expsort(*savelastp);
1159 while (sp->next != NULL)
1160 sp = sp->next;
1161 exparg.lastp = &sp->next;
1162 }
1163 str = str->next;
1164 }
1165}
1166
1167
1168/*
1169 * Do metacharacter (i.e. *, ?, [...]) expansion.
1170 */
1171
99512ac4 1172static void
984263bc
MD
1173expmeta(char *enddir, char *name)
1174{
1175 char *p;
99512ac4 1176 char *q;
984263bc
MD
1177 char *start;
1178 char *endname;
1179 int metaflag;
1180 struct stat statb;
1181 DIR *dirp;
1182 struct dirent *dp;
1183 int atend;
1184 int matchdot;
99512ac4 1185 int esc;
984263bc
MD
1186
1187 metaflag = 0;
1188 start = name;
99512ac4 1189 for (p = name; esc = 0, *p; p += esc + 1) {
984263bc
MD
1190 if (*p == '*' || *p == '?')
1191 metaflag = 1;
1192 else if (*p == '[') {
1193 q = p + 1;
1194 if (*q == '!' || *q == '^')
1195 q++;
1196 for (;;) {
1197 while (*q == CTLQUOTEMARK)
1198 q++;
1199 if (*q == CTLESC)
1200 q++;
1201 if (*q == '/' || *q == '\0')
1202 break;
1203 if (*++q == ']') {
1204 metaflag = 1;
1205 break;
1206 }
1207 }
984263bc
MD
1208 } else if (*p == '\0')
1209 break;
1210 else if (*p == CTLQUOTEMARK)
1211 continue;
99512ac4
PA
1212 else {
1213 if (*p == CTLESC)
1214 esc++;
1215 if (p[esc] == '/') {
1216 if (metaflag)
1217 break;
1218 start = p + esc + 1;
1219 }
984263bc
MD
1220 }
1221 }
1222 if (metaflag == 0) { /* we've reached the end of the file name */
1223 if (enddir != expdir)
1224 metaflag++;
1225 for (p = name ; ; p++) {
1226 if (*p == CTLQUOTEMARK)
1227 continue;
1228 if (*p == CTLESC)
1229 p++;
1230 *enddir++ = *p;
1231 if (*p == '\0')
1232 break;
99512ac4
PA
1233 if (enddir == expdir_end)
1234 return;
984263bc 1235 }
85ef70cf 1236 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
984263bc
MD
1237 addfname(expdir);
1238 return;
1239 }
1240 endname = p;
1241 if (start != name) {
1242 p = name;
1243 while (p < start) {
1244 while (*p == CTLQUOTEMARK)
1245 p++;
1246 if (*p == CTLESC)
1247 p++;
1248 *enddir++ = *p++;
99512ac4
PA
1249 if (enddir == expdir_end)
1250 return;
984263bc
MD
1251 }
1252 }
1253 if (enddir == expdir) {
99512ac4 1254 p = __DECONST(char *, ".");
984263bc 1255 } else if (enddir == expdir + 1 && *expdir == '/') {
99512ac4 1256 p = __DECONST(char *, "/");
984263bc 1257 } else {
99512ac4 1258 p = expdir;
984263bc
MD
1259 enddir[-1] = '\0';
1260 }
99512ac4 1261 if ((dirp = opendir(p)) == NULL)
984263bc
MD
1262 return;
1263 if (enddir != expdir)
1264 enddir[-1] = '/';
1265 if (*endname == 0) {
1266 atend = 1;
1267 } else {
1268 atend = 0;
99512ac4
PA
1269 *endname = '\0';
1270 endname += esc + 1;
984263bc
MD
1271 }
1272 matchdot = 0;
1273 p = start;
1274 while (*p == CTLQUOTEMARK)
1275 p++;
1276 if (*p == CTLESC)
1277 p++;
1278 if (*p == '.')
1279 matchdot++;
1280 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1281 if (dp->d_name[0] == '.' && ! matchdot)
1282 continue;
1283 if (patmatch(start, dp->d_name, 0)) {
99512ac4
PA
1284 if (enddir + dp->d_namlen + 1 > expdir_end)
1285 continue;
1286 memcpy(enddir, dp->d_name, dp->d_namlen + 1);
1287 if (atend)
984263bc 1288 addfname(expdir);
99512ac4
PA
1289 else {
1290 if (enddir + dp->d_namlen + 2 > expdir_end)
984263bc 1291 continue;
99512ac4
PA
1292 enddir[dp->d_namlen] = '/';
1293 enddir[dp->d_namlen + 1] = '\0';
1294 expmeta(enddir + dp->d_namlen + 1, endname);
984263bc
MD
1295 }
1296 }
1297 }
1298 closedir(dirp);
1299 if (! atend)
99512ac4 1300 endname[-esc - 1] = esc ? CTLESC : '/';
984263bc
MD
1301}
1302
1303
1304/*
1305 * Add a file name to the list.
1306 */
1307
99512ac4 1308static void
984263bc
MD
1309addfname(char *name)
1310{
1311 char *p;
1312 struct strlist *sp;
1313
1314 p = stalloc(strlen(name) + 1);
1315 scopy(name, p);
1316 sp = (struct strlist *)stalloc(sizeof *sp);
1317 sp->text = p;
1318 *exparg.lastp = sp;
1319 exparg.lastp = &sp->next;
1320}
1321
1322
1323/*
1324 * Sort the results of file name expansion. It calculates the number of
1325 * strings to sort and then calls msort (short for merge sort) to do the
1326 * work.
1327 */
1328
99512ac4 1329static struct strlist *
984263bc
MD
1330expsort(struct strlist *str)
1331{
1332 int len;
1333 struct strlist *sp;
1334
1335 len = 0;
1336 for (sp = str ; sp ; sp = sp->next)
1337 len++;
1338 return msort(str, len);
1339}
1340
1341
99512ac4 1342static struct strlist *
984263bc
MD
1343msort(struct strlist *list, int len)
1344{
1345 struct strlist *p, *q = NULL;
1346 struct strlist **lpp;
1347 int half;
1348 int n;
1349
1350 if (len <= 1)
1351 return list;
1352 half = len >> 1;
1353 p = list;
1354 for (n = half ; --n >= 0 ; ) {
1355 q = p;
1356 p = p->next;
1357 }
1358 q->next = NULL; /* terminate first half of list */
1359 q = msort(list, half); /* sort first half of list */
1360 p = msort(p, len - half); /* sort second half */
1361 lpp = &list;
1362 for (;;) {
1363 if (strcmp(p->text, q->text) < 0) {
1364 *lpp = p;
1365 lpp = &p->next;
1366 if ((p = *lpp) == NULL) {
1367 *lpp = q;
1368 break;
1369 }
1370 } else {
1371 *lpp = q;
1372 lpp = &q->next;
1373 if ((q = *lpp) == NULL) {
1374 *lpp = p;
1375 break;
1376 }
1377 }
1378 }
1379 return list;
1380}
1381
1382
1383
ead7935b
PA
1384static wchar_t
1385get_wc(const char **p)
1386{
1387 wchar_t c;
1388 int chrlen;
1389
1390 chrlen = mbtowc(&c, *p, 4);
1391 if (chrlen == 0)
1392 return 0;
1393 else if (chrlen == -1)
1394 c = 0;
1395 else
1396 *p += chrlen;
1397 return c;
1398}
1399
1400
984263bc
MD
1401/*
1402 * Returns true if the pattern matches the string.
1403 */
1404
1405int
99512ac4 1406patmatch(const char *pattern, const char *string, int squoted)
984263bc 1407{
99512ac4 1408 const char *p, *q;
984263bc 1409 char c;
ead7935b 1410 wchar_t wc, wc2;
984263bc
MD
1411
1412 p = pattern;
1413 q = string;
1414 for (;;) {
1415 switch (c = *p++) {
1416 case '\0':
1417 goto breakloop;
1418 case CTLESC:
1419 if (squoted && *q == CTLESC)
1420 q++;
1421 if (*q++ != *p++)
1422 return 0;
1423 break;
1424 case CTLQUOTEMARK:
1425 continue;
1426 case '?':
1427 if (squoted && *q == CTLESC)
1428 q++;
ead7935b
PA
1429 if (localeisutf8)
1430 wc = get_wc(&q);
1431 else
1432 wc = (unsigned char)*q++;
1433 if (wc == '\0')
984263bc
MD
1434 return 0;
1435 break;
1436 case '*':
1437 c = *p;
1438 while (c == CTLQUOTEMARK || c == '*')
1439 c = *++p;
1440 if (c != CTLESC && c != CTLQUOTEMARK &&
1441 c != '?' && c != '*' && c != '[') {
1442 while (*q != c) {
1443 if (squoted && *q == CTLESC &&
1444 q[1] == c)
1445 break;
1446 if (*q == '\0')
1447 return 0;
1448 if (squoted && *q == CTLESC)
1449 q++;
1450 q++;
1451 }
1452 }
1453 do {
99512ac4 1454 if (patmatch(p, q, squoted))
984263bc
MD
1455 return 1;
1456 if (squoted && *q == CTLESC)
1457 q++;
1458 } while (*q++ != '\0');
1459 return 0;
1460 case '[': {
99512ac4 1461 const char *endp;
984263bc 1462 int invert, found;
ead7935b 1463 wchar_t chr;
984263bc
MD
1464
1465 endp = p;
1466 if (*endp == '!' || *endp == '^')
1467 endp++;
1468 for (;;) {
1469 while (*endp == CTLQUOTEMARK)
1470 endp++;
1471 if (*endp == '\0')
1472 goto dft; /* no matching ] */
1473 if (*endp == CTLESC)
1474 endp++;
1475 if (*++endp == ']')
1476 break;
1477 }
1478 invert = 0;
1479 if (*p == '!' || *p == '^') {
1480 invert++;
1481 p++;
1482 }
1483 found = 0;
ead7935b
PA
1484 if (squoted && *q == CTLESC)
1485 q++;
1486 if (localeisutf8)
1487 chr = get_wc(&q);
1488 else
1489 chr = (unsigned char)*q++;
984263bc
MD
1490 if (chr == '\0')
1491 return 0;
1492 c = *p++;
1493 do {
1494 if (c == CTLQUOTEMARK)
1495 continue;
1496 if (c == CTLESC)
1497 c = *p++;
ead7935b
PA
1498 if (localeisutf8 && c & 0x80) {
1499 p--;
1500 wc = get_wc(&p);
1501 if (wc == 0) /* bad utf-8 */
1502 return 0;
1503 } else
1504 wc = (unsigned char)c;
984263bc
MD
1505 if (*p == '-' && p[1] != ']') {
1506 p++;
1507 while (*p == CTLQUOTEMARK)
1508 p++;
1509 if (*p == CTLESC)
1510 p++;
ead7935b
PA
1511 if (localeisutf8) {
1512 wc2 = get_wc(&p);
1513 if (wc2 == 0) /* bad utf-8 */
1514 return 0;
1515 } else
1516 wc2 = (unsigned char)*p++;
1517 if ( collate_range_cmp(chr, wc) >= 0
1518 && collate_range_cmp(chr, wc2) <= 0
984263bc
MD
1519 )
1520 found = 1;
984263bc 1521 } else {
ead7935b 1522 if (chr == wc)
984263bc
MD
1523 found = 1;
1524 }
1525 } while ((c = *p++) != ']');
1526 if (found == invert)
1527 return 0;
1528 break;
1529 }
1530dft: default:
1531 if (squoted && *q == CTLESC)
1532 q++;
1533 if (*q++ != c)
1534 return 0;
1535 break;
1536 }
1537 }
1538breakloop:
1539 if (*q != '\0')
1540 return 0;
1541 return 1;
1542}
1543
1544
1545
1546/*
99512ac4 1547 * Remove any CTLESC and CTLQUOTEMARK characters from a string.
984263bc
MD
1548 */
1549
1550void
1551rmescapes(char *str)
1552{
1553 char *p, *q;
1554
1555 p = str;
99512ac4 1556 while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
984263bc
MD
1557 if (*p++ == '\0')
1558 return;
1559 }
1560 q = p;
1561 while (*p) {
99512ac4 1562 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
984263bc
MD
1563 p++;
1564 continue;
1565 }
1566 if (*p == CTLESC)
1567 p++;
1568 *q++ = *p++;
1569 }
1570 *q = '\0';
1571}
1572
1573
1574
1575/*
1576 * See if a pattern matches in a case statement.
1577 */
1578
1579int
99512ac4 1580casematch(union node *pattern, const char *val)
984263bc
MD
1581{
1582 struct stackmark smark;
1583 int result;
1584 char *p;
1585
1586 setstackmark(&smark);
1587 argbackq = pattern->narg.backquote;
1588 STARTSTACKSTR(expdest);
1589 ifslastp = NULL;
1590 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1591 STPUTC('\0', expdest);
1592 p = grabstackstr(expdest);
1593 result = patmatch(p, val, 0);
1594 popstackmark(&smark);
1595 return result;
1596}
1597
1598/*
1599 * Our own itoa().
1600 */
1601
99512ac4 1602static char *
984263bc
MD
1603cvtnum(int num, char *buf)
1604{
1605 char temp[32];
1606 int neg = num < 0;
1607 char *p = temp + 31;
1608
1609 temp[31] = '\0';
1610
1611 do {
1612 *--p = num % 10 + '0';
1613 } while ((num /= 10) != 0);
1614
1615 if (neg)
1616 *--p = '-';
1617
99512ac4 1618 STPUTS(p, buf);
984263bc
MD
1619 return buf;
1620}
d13d0ee2
PA
1621
1622/*
1623 * Do most of the work for wordexp(3).
1624 */
1625
1626int
1627wordexpcmd(int argc, char **argv)
1628{
1629 size_t len;
1630 int i;
1631
1632 out1fmt("%08x", argc - 1);
1633 for (i = 1, len = 0; i < argc; i++)
1634 len += strlen(argv[i]);
1635 out1fmt("%08x", (int)len);
99512ac4
PA
1636 for (i = 1; i < argc; i++)
1637 outbin(argv[i], strlen(argv[i]) + 1, out1);
d13d0ee2
PA
1638 return (0);
1639}