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