Tue Oct 8 03:52:44 2019 UTC ()
Open code the validity test & copy of the character class name in
a bracket expression in a pattern (ie: [[:THISNAME:]]).   Previously
the code used strspn() to look for invalid chars in the name, and
then memcpy(), now we do the test and copy a character at a time.
This might, or might not, be faster, but it now correctly handles
\ quoted characters in the name (' and " quoting were already
dealt with, \ was too in an earlier version, but when the \ handling
changes were made, this piece of code broke).

Not exactly a vital bug fix (who writes [[:\alpha:]] or similar?)
but it should work correctly regardless of how obscure the usage is.

Problem noted by Harald van Dijk

XXX pullup -9


(kre)
diff -r1.132 -r1.133 src/bin/sh/expand.c

cvs diff -r1.132 -r1.133 src/bin/sh/expand.c (switch to unified diff)

--- src/bin/sh/expand.c 2019/04/10 08:13:11 1.132
+++ src/bin/sh/expand.c 2019/10/08 03:52:44 1.133
@@ -1,2191 +1,2211 @@ @@ -1,2191 +1,2211 @@
1/* $NetBSD: expand.c,v 1.132 2019/04/10 08:13:11 kre Exp $ */ 1/* $NetBSD: expand.c,v 1.133 2019/10/08 03:52:44 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1991, 1993 4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; 38static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
39#else 39#else
40__RCSID("$NetBSD: expand.c,v 1.132 2019/04/10 08:13:11 kre Exp $"); 40__RCSID("$NetBSD: expand.c,v 1.133 2019/10/08 03:52:44 kre Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <sys/types.h> 44#include <sys/types.h>
45#include <sys/time.h> 45#include <sys/time.h>
46#include <sys/stat.h> 46#include <sys/stat.h>
47#include <errno.h> 47#include <errno.h>
48#include <dirent.h> 48#include <dirent.h>
49#include <unistd.h> 49#include <unistd.h>
50#include <pwd.h> 50#include <pwd.h>
51#include <limits.h> 51#include <limits.h>
52#include <stdlib.h> 52#include <stdlib.h>
53#include <stdio.h> 53#include <stdio.h>
54#include <wctype.h> 54#include <wctype.h>
55#include <wchar.h> 55#include <wchar.h>
56 56
57/* 57/*
58 * Routines to expand arguments to commands. We have to deal with 58 * Routines to expand arguments to commands. We have to deal with
59 * backquotes, shell variables, and file metacharacters. 59 * backquotes, shell variables, and file metacharacters.
60 */ 60 */
61 61
62#include "shell.h" 62#include "shell.h"
63#include "main.h" 63#include "main.h"
64#include "nodes.h" 64#include "nodes.h"
65#include "eval.h" 65#include "eval.h"
66#include "expand.h" 66#include "expand.h"
67#include "syntax.h" 67#include "syntax.h"
68#include "arithmetic.h" 68#include "arithmetic.h"
69#include "parser.h" 69#include "parser.h"
70#include "jobs.h" 70#include "jobs.h"
71#include "options.h" 71#include "options.h"
72#include "builtins.h" 72#include "builtins.h"
73#include "var.h" 73#include "var.h"
74#include "input.h" 74#include "input.h"
75#include "output.h" 75#include "output.h"
76#include "memalloc.h" 76#include "memalloc.h"
77#include "error.h" 77#include "error.h"
78#include "mystring.h" 78#include "mystring.h"
79#include "show.h" 79#include "show.h"
80 80
81/* 81/*
82 * Structure specifying which parts of the string should be searched 82 * Structure specifying which parts of the string should be searched
83 * for IFS characters. 83 * for IFS characters.
84 */ 84 */
85 85
86struct ifsregion { 86struct ifsregion {
87 struct ifsregion *next; /* next region in list */ 87 struct ifsregion *next; /* next region in list */
88 int begoff; /* offset of start of region */ 88 int begoff; /* offset of start of region */
89 int endoff; /* offset of end of region */ 89 int endoff; /* offset of end of region */
90 int inquotes; /* search for nul bytes only */ 90 int inquotes; /* search for nul bytes only */
91}; 91};
92 92
93 93
94char *expdest; /* output of current string */ 94char *expdest; /* output of current string */
95struct nodelist *argbackq; /* list of back quote expressions */ 95struct nodelist *argbackq; /* list of back quote expressions */
96struct ifsregion ifsfirst; /* first struct in list of ifs regions */ 96struct ifsregion ifsfirst; /* first struct in list of ifs regions */
97struct ifsregion *ifslastp; /* last struct in list */ 97struct ifsregion *ifslastp; /* last struct in list */
98struct arglist exparg; /* holds expanded arg list */ 98struct arglist exparg; /* holds expanded arg list */
99 99
100static int empty_dollar_at; /* have expanded "$@" to nothing */ 100static int empty_dollar_at; /* have expanded "$@" to nothing */
101 101
102STATIC const char *argstr(const char *, int); 102STATIC const char *argstr(const char *, int);
103STATIC const char *exptilde(const char *, int); 103STATIC const char *exptilde(const char *, int);
104STATIC void expbackq(union node *, int, int); 104STATIC void expbackq(union node *, int, int);
105STATIC const char *expari(const char *); 105STATIC const char *expari(const char *);
106STATIC int subevalvar(const char *, const char *, int, int, int); 106STATIC int subevalvar(const char *, const char *, int, int, int);
107STATIC int subevalvar_trim(const char *, int, int, int, int, int); 107STATIC int subevalvar_trim(const char *, int, int, int, int, int);
108STATIC const char *evalvar(const char *, int); 108STATIC const char *evalvar(const char *, int);
109STATIC int varisset(const char *, int); 109STATIC int varisset(const char *, int);
110STATIC void varvalue(const char *, int, int, int); 110STATIC void varvalue(const char *, int, int, int);
111STATIC void recordregion(int, int, int); 111STATIC void recordregion(int, int, int);
112STATIC void removerecordregions(int); 112STATIC void removerecordregions(int);
113STATIC void ifsbreakup(char *, struct arglist *); 113STATIC void ifsbreakup(char *, struct arglist *);
114STATIC void ifsfree(void); 114STATIC void ifsfree(void);
115STATIC void expandmeta(struct strlist *, int); 115STATIC void expandmeta(struct strlist *, int);
116STATIC void expmeta(char *, char *); 116STATIC void expmeta(char *, char *);
117STATIC void addfname(char *); 117STATIC void addfname(char *);
118STATIC struct strlist *expsort(struct strlist *); 118STATIC struct strlist *expsort(struct strlist *);
119STATIC struct strlist *msort(struct strlist *, int); 119STATIC struct strlist *msort(struct strlist *, int);
120STATIC int patmatch(const char *, const char *, int); 120STATIC int patmatch(const char *, const char *, int);
121STATIC char *cvtnum(int, char *); 121STATIC char *cvtnum(int, char *);
122static int collate_range_cmp(wchar_t, wchar_t); 122static int collate_range_cmp(wchar_t, wchar_t);
123STATIC void add_args(struct strlist *); 123STATIC void add_args(struct strlist *);
124STATIC void rmescapes_nl(char *); 124STATIC void rmescapes_nl(char *);
125 125
126#ifdef DEBUG 126#ifdef DEBUG
127#define NULLTERM_4_TRACE(p) STACKSTRNUL(p) 127#define NULLTERM_4_TRACE(p) STACKSTRNUL(p)
128#else 128#else
129#define NULLTERM_4_TRACE(p) do { /* nothing */ } while (/*CONSTCOND*/0) 129#define NULLTERM_4_TRACE(p) do { /* nothing */ } while (/*CONSTCOND*/0)
130#endif 130#endif
131 131
132#define IS_BORING(_ch) \ 132#define IS_BORING(_ch) \
133 ((_ch) == CTLQUOTEMARK || (_ch) == CTLQUOTEEND || (_ch) == CTLNONL) 133 ((_ch) == CTLQUOTEMARK || (_ch) == CTLQUOTEEND || (_ch) == CTLNONL)
134#define SKIP_BORING(p) \ 134#define SKIP_BORING(p) \
135 do { \ 135 do { \
136 char _ch; \ 136 char _ch; \
137 \ 137 \
138 while ((_ch = *(p)), IS_BORING(_ch)) \ 138 while ((_ch = *(p)), IS_BORING(_ch)) \
139 (p)++; \ 139 (p)++; \
140 } while (0) 140 } while (0)
141 141
142/* 142/*
143 * Expand shell variables and backquotes inside a here document. 143 * Expand shell variables and backquotes inside a here document.
144 */ 144 */
145 145
146void 146void
147expandhere(union node *arg, int fd) 147expandhere(union node *arg, int fd)
148{ 148{
149 149
150 herefd = fd; 150 herefd = fd;
151 expandarg(arg, NULL, 0); 151 expandarg(arg, NULL, 0);
152 xwrite(fd, stackblock(), expdest - stackblock()); 152 xwrite(fd, stackblock(), expdest - stackblock());
153} 153}
154 154
155 155
156static int 156static int
157collate_range_cmp(wchar_t c1, wchar_t c2) 157collate_range_cmp(wchar_t c1, wchar_t c2)
158{ 158{
159 wchar_t s1[2], s2[2]; 159 wchar_t s1[2], s2[2];
160 160
161 s1[0] = c1; 161 s1[0] = c1;
162 s1[1] = L'\0'; 162 s1[1] = L'\0';
163 s2[0] = c2; 163 s2[0] = c2;
164 s2[1] = L'\0'; 164 s2[1] = L'\0';
165 return (wcscoll(s1, s2)); 165 return (wcscoll(s1, s2));
166} 166}
167 167
168/* 168/*
169 * Perform variable substitution and command substitution on an argument, 169 * Perform variable substitution and command substitution on an argument,
170 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 170 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
171 * perform splitting and file name expansion. When arglist is NULL, perform 171 * perform splitting and file name expansion. When arglist is NULL, perform
172 * here document expansion. 172 * here document expansion.
173 */ 173 */
174 174
175void 175void
176expandarg(union node *arg, struct arglist *arglist, int flag) 176expandarg(union node *arg, struct arglist *arglist, int flag)
177{ 177{
178 struct strlist *sp; 178 struct strlist *sp;
179 char *p; 179 char *p;
180 180
181 CTRACE(DBG_EXPAND, ("expandarg(fl=%#x)\n", flag)); 181 CTRACE(DBG_EXPAND, ("expandarg(fl=%#x)\n", flag));
182 if (fflag) /* no filename expandsion */ 182 if (fflag) /* no filename expandsion */
183 flag &= ~EXP_GLOB; 183 flag &= ~EXP_GLOB;
184 184
185 empty_dollar_at = 0; 185 empty_dollar_at = 0;
186 argbackq = arg->narg.backquote; 186 argbackq = arg->narg.backquote;
187 STARTSTACKSTR(expdest); 187 STARTSTACKSTR(expdest);
188 ifsfirst.next = NULL; 188 ifsfirst.next = NULL;
189 ifslastp = NULL; 189 ifslastp = NULL;
190 line_number = arg->narg.lineno; 190 line_number = arg->narg.lineno;
191 argstr(arg->narg.text, flag); 191 argstr(arg->narg.text, flag);
192 if (arglist == NULL) { 192 if (arglist == NULL) {
193 STACKSTRNUL(expdest); 193 STACKSTRNUL(expdest);
194 CTRACE(DBG_EXPAND, ("expandarg: no arglist, done (%d) \"%s\"\n", 194 CTRACE(DBG_EXPAND, ("expandarg: no arglist, done (%d) \"%s\"\n",
195 expdest - stackblock(), stackblock())); 195 expdest - stackblock(), stackblock()));
196 return; /* here document expanded */ 196 return; /* here document expanded */
197 } 197 }
198 STPUTC('\0', expdest); 198 STPUTC('\0', expdest);
199 CTRACE(DBG_EXPAND, ("expandarg: arglist got (%d) \"%s\"\n", 199 CTRACE(DBG_EXPAND, ("expandarg: arglist got (%d) \"%s\"\n",
200 expdest - stackblock() - 1, stackblock())); 200 expdest - stackblock() - 1, stackblock()));
201 p = grabstackstr(expdest); 201 p = grabstackstr(expdest);
202 exparg.lastp = &exparg.list; 202 exparg.lastp = &exparg.list;
203 /* 203 /*
204 * TODO - EXP_REDIR 204 * TODO - EXP_REDIR
205 */ 205 */
206 if (flag & EXP_SPLIT) { 206 if (flag & EXP_SPLIT) {
207 ifsbreakup(p, &exparg); 207 ifsbreakup(p, &exparg);
208 *exparg.lastp = NULL; 208 *exparg.lastp = NULL;
209 exparg.lastp = &exparg.list; 209 exparg.lastp = &exparg.list;
210 if (flag & EXP_GLOB) 210 if (flag & EXP_GLOB)
211 expandmeta(exparg.list, flag); 211 expandmeta(exparg.list, flag);
212 else 212 else
213 add_args(exparg.list); 213 add_args(exparg.list);
214#if 0 214#if 0
215 } else if (flag & EXP_REDIR) { 215 } else if (flag & EXP_REDIR) {
216 /* if EXP_REDIR ever happens, it happens here */ 216 /* if EXP_REDIR ever happens, it happens here */
217 /* for now just (below) remove escapes, and leave it alone */ 217 /* for now just (below) remove escapes, and leave it alone */
218#endif 218#endif
219 } else { 219 } else {
220 rmescapes(p); /* we might have escaped CTL bytes to remove */ 220 rmescapes(p); /* we might have escaped CTL bytes to remove */
221 sp = stalloc(sizeof(*sp)); 221 sp = stalloc(sizeof(*sp));
222 sp->text = p; 222 sp->text = p;
223 *exparg.lastp = sp; 223 *exparg.lastp = sp;
224 exparg.lastp = &sp->next; 224 exparg.lastp = &sp->next;
225 } 225 }
226 ifsfree(); 226 ifsfree();
227 *exparg.lastp = NULL; 227 *exparg.lastp = NULL;
228 if (exparg.list) { 228 if (exparg.list) {
229 *arglist->lastp = exparg.list; 229 *arglist->lastp = exparg.list;
230 arglist->lastp = exparg.lastp; 230 arglist->lastp = exparg.lastp;
231 } 231 }
232} 232}
233 233
234 234
235 235
236/* 236/*
237 * Perform variable and command substitution. 237 * Perform variable and command substitution.
238 * If EXP_GLOB is set, output CTLESC characters to allow for further processing. 238 * If EXP_GLOB is set, output CTLESC characters to allow for further processing.
239 * If EXP_SPLIT is set, remember location of result for later, 239 * If EXP_SPLIT is set, remember location of result for later,
240 * Otherwise treat $@ like $* since no splitting will be performed. 240 * Otherwise treat $@ like $* since no splitting will be performed.
241 */ 241 */
242 242
243STATIC const char * 243STATIC const char *
244argstr(const char *p, int flag) 244argstr(const char *p, int flag)
245{ 245{
246 char c; 246 char c;
247 const int quotes = flag & EXP_QNEEDED; /* do CTLESC */ 247 const int quotes = flag & EXP_QNEEDED; /* do CTLESC */
248 int firsteq = 1; 248 int firsteq = 1;
249 int had_dol_at = 0; 249 int had_dol_at = 0;
250 int startoff; 250 int startoff;
251 const char *ifs = NULL; 251 const char *ifs = NULL;
252 int ifs_split = EXP_IFS_SPLIT; 252 int ifs_split = EXP_IFS_SPLIT;
253 253
254 if (flag & EXP_IFS_SPLIT) 254 if (flag & EXP_IFS_SPLIT)
255 ifs = ifsval(); 255 ifs = ifsval();
256 256
257 CTRACE(DBG_EXPAND, ("argstr(\"%s\", %#x) quotes=%#x\n", p,flag,quotes)); 257 CTRACE(DBG_EXPAND, ("argstr(\"%s\", %#x) quotes=%#x\n", p,flag,quotes));
258 258
259 startoff = expdest - stackblock(); 259 startoff = expdest - stackblock();
260 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) 260 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
261 p = exptilde(p, flag); 261 p = exptilde(p, flag);
262 for (;;) { 262 for (;;) {
263 switch (c = *p++) { 263 switch (c = *p++) {
264 case '\0': 264 case '\0':
265 NULLTERM_4_TRACE(expdest); 265 NULLTERM_4_TRACE(expdest);
266 VTRACE(DBG_EXPAND, ("argstr returning at \"\" " 266 VTRACE(DBG_EXPAND, ("argstr returning at \"\" "
267 "added \"%s\" to expdest\n", stackblock())); 267 "added \"%s\" to expdest\n", stackblock()));
268 return p - 1; 268 return p - 1;
269 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ 269 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
270 case CTLENDARI: /* end of a $(( )) string */ 270 case CTLENDARI: /* end of a $(( )) string */
271 if (had_dol_at && (*p&0xFF) == CTLQUOTEEND) 271 if (had_dol_at && (*p&0xFF) == CTLQUOTEEND)
272 p++; 272 p++;
273 NULLTERM_4_TRACE(expdest); 273 NULLTERM_4_TRACE(expdest);
274 VTRACE(DBG_EXPAND, ("argstr returning at \"%.6s\"..." 274 VTRACE(DBG_EXPAND, ("argstr returning at \"%.6s\"..."
275 " after %2.2X; added \"%s\" to expdest\n", 275 " after %2.2X; added \"%s\" to expdest\n",
276 p, (c&0xff), stackblock())); 276 p, (c&0xff), stackblock()));
277 return p; 277 return p;
278 case CTLQUOTEMARK: 278 case CTLQUOTEMARK:
279 /* "$@" syntax adherence hack */ 279 /* "$@" syntax adherence hack */
280 if (p[0] == CTLVAR && p[1] & VSQUOTE && 280 if (p[0] == CTLVAR && p[1] & VSQUOTE &&
281 p[2] == '@' && p[3] == '=') { 281 p[2] == '@' && p[3] == '=') {
282 had_dol_at = 1; 282 had_dol_at = 1;
283 break; 283 break;
284 } 284 }
285 had_dol_at = 0; 285 had_dol_at = 0;
286 empty_dollar_at = 0; 286 empty_dollar_at = 0;
287 if ((flag & EXP_SPLIT) != 0) 287 if ((flag & EXP_SPLIT) != 0)
288 STPUTC(c, expdest); 288 STPUTC(c, expdest);
289 ifs_split = 0; 289 ifs_split = 0;
290 break; 290 break;
291 case CTLNONL: 291 case CTLNONL:
292 if (flag & EXP_NL) 292 if (flag & EXP_NL)
293 STPUTC(c, expdest); 293 STPUTC(c, expdest);
294 line_number++; 294 line_number++;
295 break; 295 break;
296 case CTLCNL: 296 case CTLCNL:
297 STPUTC('\n', expdest); /* no line_number++ */ 297 STPUTC('\n', expdest); /* no line_number++ */
298 break; 298 break;
299 case CTLQUOTEEND: 299 case CTLQUOTEEND:
300 if (empty_dollar_at && 300 if (empty_dollar_at &&
301 expdest - stackblock() > startoff && 301 expdest - stackblock() > startoff &&
302 expdest[-1] == CTLQUOTEMARK) 302 expdest[-1] == CTLQUOTEMARK)
303 expdest--; 303 expdest--;
304 else if (!had_dol_at && (flag & EXP_SPLIT) != 0) 304 else if (!had_dol_at && (flag & EXP_SPLIT) != 0)
305 STPUTC(c, expdest); 305 STPUTC(c, expdest);
306 ifs_split = EXP_IFS_SPLIT; 306 ifs_split = EXP_IFS_SPLIT;
307 had_dol_at = 0; 307 had_dol_at = 0;
308 break; 308 break;
309 case CTLESC: 309 case CTLESC:
310 if (quotes || ISCTL(*p)) 310 if (quotes || ISCTL(*p))
311 STPUTC(c, expdest); 311 STPUTC(c, expdest);
312 c = *p++; 312 c = *p++;
313 STPUTC(c, expdest); 313 STPUTC(c, expdest);
314 if (c == '\n') /* should not happen, but ... */ 314 if (c == '\n') /* should not happen, but ... */
315 line_number++; 315 line_number++;
316 break; 316 break;
317 case CTLVAR: { 317 case CTLVAR: {
318#ifdef DEBUG 318#ifdef DEBUG
319 unsigned int pos = expdest - stackblock(); 319 unsigned int pos = expdest - stackblock();
320 NULLTERM_4_TRACE(expdest); 320 NULLTERM_4_TRACE(expdest);
321#endif 321#endif
322 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split)); 322 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
323 NULLTERM_4_TRACE(expdest); 323 NULLTERM_4_TRACE(expdest);
324 VTRACE(DBG_EXPAND, ("argstr evalvar " 324 VTRACE(DBG_EXPAND, ("argstr evalvar "
325 "added %zd \"%s\" to expdest\n", 325 "added %zd \"%s\" to expdest\n",
326 (size_t)(expdest - (stackblock() + pos)), 326 (size_t)(expdest - (stackblock() + pos)),
327 stackblock() + pos)); 327 stackblock() + pos));
328 break; 328 break;
329 } 329 }
330 case CTLBACKQ: 330 case CTLBACKQ:
331 case CTLBACKQ|CTLQUOTE: { 331 case CTLBACKQ|CTLQUOTE: {
332#ifdef DEBUG 332#ifdef DEBUG
333 unsigned int pos = expdest - stackblock(); 333 unsigned int pos = expdest - stackblock();
334#endif 334#endif
335 expbackq(argbackq->n, c & CTLQUOTE, flag); 335 expbackq(argbackq->n, c & CTLQUOTE, flag);
336 argbackq = argbackq->next; 336 argbackq = argbackq->next;
337 NULLTERM_4_TRACE(expdest); 337 NULLTERM_4_TRACE(expdest);
338 VTRACE(DBG_EXPAND, ("argstr expbackq added \"%s\" " 338 VTRACE(DBG_EXPAND, ("argstr expbackq added \"%s\" "
339 "to expdest\n", stackblock() + pos)); 339 "to expdest\n", stackblock() + pos));
340 break; 340 break;
341 } 341 }
342 case CTLARI: { 342 case CTLARI: {
343#ifdef DEBUG 343#ifdef DEBUG
344 unsigned int pos = expdest - stackblock(); 344 unsigned int pos = expdest - stackblock();
345#endif 345#endif
346 p = expari(p); 346 p = expari(p);
347 NULLTERM_4_TRACE(expdest); 347 NULLTERM_4_TRACE(expdest);
348 VTRACE(DBG_EXPAND, ("argstr expari " 348 VTRACE(DBG_EXPAND, ("argstr expari "
349 "+ \"%s\" to expdest p=\"%.5s...\"\n", 349 "+ \"%s\" to expdest p=\"%.5s...\"\n",
350 stackblock() + pos, p)); 350 stackblock() + pos, p));
351 break; 351 break;
352 } 352 }
353 case ':': 353 case ':':
354 case '=': 354 case '=':
355 /* 355 /*
356 * sort of a hack - expand tildes in variable 356 * sort of a hack - expand tildes in variable
357 * assignments (after the first '=' and after ':'s). 357 * assignments (after the first '=' and after ':'s).
358 */ 358 */
359 STPUTC(c, expdest); 359 STPUTC(c, expdest);
360 if (flag & EXP_VARTILDE && *p == '~') { 360 if (flag & EXP_VARTILDE && *p == '~') {
361 if (c == '=') { 361 if (c == '=') {
362 if (firsteq) 362 if (firsteq)
363 firsteq = 0; 363 firsteq = 0;
364 else 364 else
365 break; 365 break;
366 } 366 }
367 p = exptilde(p, flag); 367 p = exptilde(p, flag);
368 } 368 }
369 break; 369 break;
370 default: 370 default:
371 if (c == '\n') 371 if (c == '\n')
372 line_number++; 372 line_number++;
373 STPUTC(c, expdest); 373 STPUTC(c, expdest);
374 if (flag & ifs_split && strchr(ifs, c) != NULL) { 374 if (flag & ifs_split && strchr(ifs, c) != NULL) {
375 /* We need to get the output split here... */ 375 /* We need to get the output split here... */
376 recordregion(expdest - stackblock() - 1, 376 recordregion(expdest - stackblock() - 1,
377 expdest - stackblock(), 0); 377 expdest - stackblock(), 0);
378 } 378 }
379 break; 379 break;
380 } 380 }
381 } 381 }
382} 382}
383 383
384STATIC const char * 384STATIC const char *
385exptilde(const char *p, int flag) 385exptilde(const char *p, int flag)
386{ 386{
387 char c; 387 char c;
388 const char *startp = p; 388 const char *startp = p;
389 struct passwd *pw; 389 struct passwd *pw;
390 const char *home; 390 const char *home;
391 const int quotes = flag & EXP_QNEEDED; 391 const int quotes = flag & EXP_QNEEDED;
392 char *user; 392 char *user;
393 struct stackmark smark; 393 struct stackmark smark;
394#ifdef DEBUG 394#ifdef DEBUG
395 unsigned int offs = expdest - stackblock(); 395 unsigned int offs = expdest - stackblock();
396#endif 396#endif
397 397
398 setstackmark(&smark); 398 setstackmark(&smark);
399 (void) grabstackstr(expdest); 399 (void) grabstackstr(expdest);
400 user = stackblock(); /* we will just borrow top of stack */ 400 user = stackblock(); /* we will just borrow top of stack */
401 401
402 while ((c = *++p) != '\0') { 402 while ((c = *++p) != '\0') {
403 switch(c) { 403 switch(c) {
404 case CTLESC: /* any of these occurring */ 404 case CTLESC: /* any of these occurring */
405 case CTLVAR: /* means ~ expansion */ 405 case CTLVAR: /* means ~ expansion */
406 case CTLBACKQ: /* does not happen at all */ 406 case CTLBACKQ: /* does not happen at all */
407 case CTLBACKQ | CTLQUOTE: 407 case CTLBACKQ | CTLQUOTE:
408 case CTLARI: /* just leave original unchanged */ 408 case CTLARI: /* just leave original unchanged */
409 case CTLENDARI: 409 case CTLENDARI:
410 case CTLQUOTEMARK: 410 case CTLQUOTEMARK:
411 case '\n': 411 case '\n':
412 popstackmark(&smark); 412 popstackmark(&smark);
413 return (startp); 413 return (startp);
414 case CTLNONL: 414 case CTLNONL:
415 continue; 415 continue;
416 case ':': 416 case ':':
417 if (!posix || flag & EXP_VARTILDE) 417 if (!posix || flag & EXP_VARTILDE)
418 goto done; 418 goto done;
419 break; 419 break;
420 case CTLENDVAR: 420 case CTLENDVAR:
421 case '/': 421 case '/':
422 goto done; 422 goto done;
423 } 423 }
424 STPUTC(c, user); 424 STPUTC(c, user);
425 } 425 }
426 done: 426 done:
427 STACKSTRNUL(user); 427 STACKSTRNUL(user);
428 user = stackblock(); /* to start of collected username */ 428 user = stackblock(); /* to start of collected username */
429 429
430 CTRACE(DBG_EXPAND, ("exptilde, found \"~%s\"", user)); 430 CTRACE(DBG_EXPAND, ("exptilde, found \"~%s\"", user));
431 if (*user == '\0') { 431 if (*user == '\0') {
432 home = lookupvar("HOME"); 432 home = lookupvar("HOME");
433 /* 433 /*
434 * if HOME is unset, results are unspecified... 434 * if HOME is unset, results are unspecified...
435 * we used to just leave the ~ unchanged, but 435 * we used to just leave the ~ unchanged, but
436 * (some) other shells do ... and this seems more useful. 436 * (some) other shells do ... and this seems more useful.
437 */ 437 */
438 if (home == NULL && (pw = getpwuid(getuid())) != NULL) 438 if (home == NULL && (pw = getpwuid(getuid())) != NULL)
439 home = pw->pw_dir; 439 home = pw->pw_dir;
440 } else if ((pw = getpwnam(user)) == NULL) { 440 } else if ((pw = getpwnam(user)) == NULL) {
441 /* 441 /*
442 * If user does not exist, results are undefined. 442 * If user does not exist, results are undefined.
443 * so we can abort() here if we want, but let's not! 443 * so we can abort() here if we want, but let's not!
444 */ 444 */
445 home = NULL; 445 home = NULL;
446 } else 446 } else
447 home = pw->pw_dir; 447 home = pw->pw_dir;
448 448
449 VTRACE(DBG_EXPAND, (" ->\"%s\"", home ? home : "<<NULL>>")); 449 VTRACE(DBG_EXPAND, (" ->\"%s\"", home ? home : "<<NULL>>"));
450 popstackmark(&smark); /* now expdest is valid again */ 450 popstackmark(&smark); /* now expdest is valid again */
451 451
452 /* 452 /*
453 * Posix XCU 2.6.1: The value of $HOME (for ~) or the initial 453 * Posix XCU 2.6.1: The value of $HOME (for ~) or the initial
454 * working directory from getpwnam() for ~user 454 * working directory from getpwnam() for ~user
455 * Nothing there about "except if a null string". So do what it wants. 455 * Nothing there about "except if a null string". So do what it wants.
456 */ 456 */
457 if (home == NULL /* || *home == '\0' */) { 457 if (home == NULL /* || *home == '\0' */) {
458 CTRACE(DBG_EXPAND, (": returning unused \"%s\"\n", startp)); 458 CTRACE(DBG_EXPAND, (": returning unused \"%s\"\n", startp));
459 return startp; 459 return startp;
460 } while ((c = *home++) != '\0') { 460 } while ((c = *home++) != '\0') {
461 if ((quotes && NEEDESC(c)) || ISCTL(c)) 461 if ((quotes && NEEDESC(c)) || ISCTL(c))
462 STPUTC(CTLESC, expdest); 462 STPUTC(CTLESC, expdest);
463 STPUTC(c, expdest); 463 STPUTC(c, expdest);
464 } 464 }
465 CTRACE(DBG_EXPAND, (": added %d \"%.*s\" returning \"%s\"\n", 465 CTRACE(DBG_EXPAND, (": added %d \"%.*s\" returning \"%s\"\n",
466 expdest - stackblock() - offs, expdest - stackblock() - offs, 466 expdest - stackblock() - offs, expdest - stackblock() - offs,
467 stackblock() + offs, p)); 467 stackblock() + offs, p));
468 468
469 return (p); 469 return (p);
470} 470}
471 471
472 472
473STATIC void 473STATIC void
474removerecordregions(int endoff) 474removerecordregions(int endoff)
475{ 475{
476 476
477 VTRACE(DBG_EXPAND, ("removerecordregions(%d):", endoff)); 477 VTRACE(DBG_EXPAND, ("removerecordregions(%d):", endoff));
478 if (ifslastp == NULL) { 478 if (ifslastp == NULL) {
479 VTRACE(DBG_EXPAND, (" none\n", endoff)); 479 VTRACE(DBG_EXPAND, (" none\n", endoff));
480 return; 480 return;
481 } 481 }
482 482
483 if (ifsfirst.endoff > endoff) { 483 if (ifsfirst.endoff > endoff) {
484 VTRACE(DBG_EXPAND, (" first(%d)", ifsfirst.endoff)); 484 VTRACE(DBG_EXPAND, (" first(%d)", ifsfirst.endoff));
485 while (ifsfirst.next != NULL) { 485 while (ifsfirst.next != NULL) {
486 struct ifsregion *ifsp; 486 struct ifsregion *ifsp;
487 INTOFF; 487 INTOFF;
488 ifsp = ifsfirst.next->next; 488 ifsp = ifsfirst.next->next;
489 ckfree(ifsfirst.next); 489 ckfree(ifsfirst.next);
490 ifsfirst.next = ifsp; 490 ifsfirst.next = ifsp;
491 INTON; 491 INTON;
492 } 492 }
493 if (ifsfirst.begoff > endoff) 493 if (ifsfirst.begoff > endoff)
494 ifslastp = NULL; 494 ifslastp = NULL;
495 else { 495 else {
496 VTRACE(DBG_EXPAND,("->(%d,%d)",ifsfirst.begoff,endoff)); 496 VTRACE(DBG_EXPAND,("->(%d,%d)",ifsfirst.begoff,endoff));
497 ifslastp = &ifsfirst; 497 ifslastp = &ifsfirst;
498 ifsfirst.endoff = endoff; 498 ifsfirst.endoff = endoff;
499 } 499 }
500 VTRACE(DBG_EXPAND, ("\n")); 500 VTRACE(DBG_EXPAND, ("\n"));
501 return; 501 return;
502 } 502 }
503 503
504 ifslastp = &ifsfirst; 504 ifslastp = &ifsfirst;
505 while (ifslastp->next && ifslastp->next->begoff < endoff) 505 while (ifslastp->next && ifslastp->next->begoff < endoff)
506 ifslastp=ifslastp->next; 506 ifslastp=ifslastp->next;
507 VTRACE(DBG_EXPAND, (" found(%d,%d)", ifslastp->begoff,ifslastp->endoff)); 507 VTRACE(DBG_EXPAND, (" found(%d,%d)", ifslastp->begoff,ifslastp->endoff));
508 while (ifslastp->next != NULL) { 508 while (ifslastp->next != NULL) {
509 struct ifsregion *ifsp; 509 struct ifsregion *ifsp;
510 INTOFF; 510 INTOFF;
511 ifsp = ifslastp->next->next; 511 ifsp = ifslastp->next->next;
512 ckfree(ifslastp->next); 512 ckfree(ifslastp->next);
513 ifslastp->next = ifsp; 513 ifslastp->next = ifsp;
514 INTON; 514 INTON;
515 } 515 }
516 if (ifslastp->endoff > endoff) 516 if (ifslastp->endoff > endoff)
517 ifslastp->endoff = endoff; 517 ifslastp->endoff = endoff;
518 VTRACE(DBG_EXPAND, ("->(%d,%d)", ifslastp->begoff,ifslastp->endoff)); 518 VTRACE(DBG_EXPAND, ("->(%d,%d)", ifslastp->begoff,ifslastp->endoff));
519} 519}
520 520
521 521
522/* 522/*
523 * Expand arithmetic expression. 523 * Expand arithmetic expression.
524 * 524 *
525 * In this incarnation, we start at the beginning (yes, "Let's start at the 525 * In this incarnation, we start at the beginning (yes, "Let's start at the
526 * very beginning. A very good place to start.") and collect the expression 526 * very beginning. A very good place to start.") and collect the expression
527 * until the end - which means expanding anything contained within. 527 * until the end - which means expanding anything contained within.
528 * 528 *
529 * Fortunately, argstr() just happens to do that for us... 529 * Fortunately, argstr() just happens to do that for us...
530 */ 530 */
531STATIC const char * 531STATIC const char *
532expari(const char *p) 532expari(const char *p)
533{ 533{
534 char *q, *start; 534 char *q, *start;
535 intmax_t result; 535 intmax_t result;
536 int adjustment; 536 int adjustment;
537 int begoff; 537 int begoff;
538 int quoted; 538 int quoted;
539 struct stackmark smark; 539 struct stackmark smark;
540 540
541 /* ifsfree(); */ 541 /* ifsfree(); */
542 542
543 /* 543 /*
544 * SPACE_NEEDED is enough for all possible digits (rounded up) 544 * SPACE_NEEDED is enough for all possible digits (rounded up)
545 * plus possible "-", and the terminating '\0', hence, plus 2 545 * plus possible "-", and the terminating '\0', hence, plus 2
546 * 546 *
547 * The calculation produces the number of bytes needed to 547 * The calculation produces the number of bytes needed to
548 * represent the biggest possible value, in octal. We only 548 * represent the biggest possible value, in octal. We only
549 * generate decimal, which takes (often) less digits (never more) 549 * generate decimal, which takes (often) less digits (never more)
550 * so this is safe, if occasionally slightly wasteful. 550 * so this is safe, if occasionally slightly wasteful.
551 */ 551 */
552#define SPACE_NEEDED ((int)((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 2)) 552#define SPACE_NEEDED ((int)((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 2))
553 553
554 quoted = *p++ == '"'; 554 quoted = *p++ == '"';
555 begoff = expdest - stackblock(); 555 begoff = expdest - stackblock();
556 VTRACE(DBG_EXPAND, ("expari%s: \"%s\" begoff %d\n", 556 VTRACE(DBG_EXPAND, ("expari%s: \"%s\" begoff %d\n",
557 quoted ? "(quoted)" : "", p, begoff)); 557 quoted ? "(quoted)" : "", p, begoff));
558 558
559 p = argstr(p, EXP_NL); /* expand $(( )) string */ 559 p = argstr(p, EXP_NL); /* expand $(( )) string */
560 STPUTC('\0', expdest); 560 STPUTC('\0', expdest);
561 start = stackblock() + begoff; 561 start = stackblock() + begoff;
562 562
563 removerecordregions(begoff); /* nothing there is kept */ 563 removerecordregions(begoff); /* nothing there is kept */
564 rmescapes_nl(start); /* convert CRTNONL back into \n's */ 564 rmescapes_nl(start); /* convert CRTNONL back into \n's */
565 565
566 setstackmark(&smark); 566 setstackmark(&smark);
567 q = grabstackstr(expdest); /* keep the expression while eval'ing */ 567 q = grabstackstr(expdest); /* keep the expression while eval'ing */
568 result = arith(start, line_number); 568 result = arith(start, line_number);
569 popstackmark(&smark); /* return the stack to before grab */ 569 popstackmark(&smark); /* return the stack to before grab */
570 570
571 start = stackblock() + begoff; /* block may have moved */ 571 start = stackblock() + begoff; /* block may have moved */
572 adjustment = expdest - start; 572 adjustment = expdest - start;
573 STADJUST(-adjustment, expdest); /* remove the argstr() result */ 573 STADJUST(-adjustment, expdest); /* remove the argstr() result */
574 574
575 CHECKSTRSPACE(SPACE_NEEDED, expdest); /* nb: stack block might move */ 575 CHECKSTRSPACE(SPACE_NEEDED, expdest); /* nb: stack block might move */
576 fmtstr(expdest, SPACE_NEEDED, "%"PRIdMAX, result); 576 fmtstr(expdest, SPACE_NEEDED, "%"PRIdMAX, result);
577 577
578 for (q = expdest; *q++ != '\0'; ) /* find end of what we added */ 578 for (q = expdest; *q++ != '\0'; ) /* find end of what we added */
579 ; 579 ;
580 580
581 if (quoted == 0) /* allow weird splitting */ 581 if (quoted == 0) /* allow weird splitting */
582 recordregion(begoff, begoff + q - 1 - expdest, 0); 582 recordregion(begoff, begoff + q - 1 - expdest, 0);
583 adjustment = q - expdest - 1; 583 adjustment = q - expdest - 1;
584 STADJUST(adjustment, expdest); /* move expdest to end */ 584 STADJUST(adjustment, expdest); /* move expdest to end */
585 VTRACE(DBG_EXPAND, ("expari: adding %d \"%s\", returning \"%.5s...\"\n", 585 VTRACE(DBG_EXPAND, ("expari: adding %d \"%s\", returning \"%.5s...\"\n",
586 adjustment, stackblock() + begoff, p)); 586 adjustment, stackblock() + begoff, p));
587 587
588 return p; 588 return p;
589} 589}
590 590
591 591
592/* 592/*
593 * Expand stuff in backwards quotes (these days, any command substitution). 593 * Expand stuff in backwards quotes (these days, any command substitution).
594 */ 594 */
595 595
596STATIC void 596STATIC void
597expbackq(union node *cmd, int quoted, int flag) 597expbackq(union node *cmd, int quoted, int flag)
598{ 598{
599 struct backcmd in; 599 struct backcmd in;
600 int i; 600 int i;
601 char buf[128]; 601 char buf[128];
602 char *p; 602 char *p;
603 char *dest = expdest; /* expdest may be reused by eval, use an alt */ 603 char *dest = expdest; /* expdest may be reused by eval, use an alt */
604 struct ifsregion saveifs, *savelastp; 604 struct ifsregion saveifs, *savelastp;
605 struct nodelist *saveargbackq; 605 struct nodelist *saveargbackq;
606 char lastc; 606 char lastc;
607 int startloc = dest - stackblock(); 607 int startloc = dest - stackblock();
608 int saveherefd; 608 int saveherefd;
609 const int quotes = flag & EXP_QNEEDED; 609 const int quotes = flag & EXP_QNEEDED;
610 int nnl; 610 int nnl;
611 struct stackmark smark; 611 struct stackmark smark;
612 612
613 VTRACE(DBG_EXPAND, ("expbackq( ..., q=%d flag=%#x) have %d\n", 613 VTRACE(DBG_EXPAND, ("expbackq( ..., q=%d flag=%#x) have %d\n",
614 quoted, flag, startloc)); 614 quoted, flag, startloc));
615 INTOFF; 615 INTOFF;
616 saveifs = ifsfirst; 616 saveifs = ifsfirst;
617 savelastp = ifslastp; 617 savelastp = ifslastp;
618 saveargbackq = argbackq; 618 saveargbackq = argbackq;
619 saveherefd = herefd; 619 saveherefd = herefd;
620 herefd = -1; 620 herefd = -1;
621 621
622 setstackmark(&smark); /* preserve the stack */ 622 setstackmark(&smark); /* preserve the stack */
623 p = grabstackstr(dest); /* save what we have there currently */ 623 p = grabstackstr(dest); /* save what we have there currently */
624 evalbackcmd(cmd, &in); /* evaluate the $( ) tree (using stack) */ 624 evalbackcmd(cmd, &in); /* evaluate the $( ) tree (using stack) */
625 popstackmark(&smark); /* and return stack to when we entered */ 625 popstackmark(&smark); /* and return stack to when we entered */
626 626
627 ifsfirst = saveifs; 627 ifsfirst = saveifs;
628 ifslastp = savelastp; 628 ifslastp = savelastp;
629 argbackq = saveargbackq; 629 argbackq = saveargbackq;
630 herefd = saveherefd; 630 herefd = saveherefd;
631 631
632 p = in.buf; /* now extract the results */ 632 p = in.buf; /* now extract the results */
633 nnl = 0; /* dropping trailing \n's */ 633 nnl = 0; /* dropping trailing \n's */
634 for (;;) { 634 for (;;) {
635 if (--in.nleft < 0) { 635 if (--in.nleft < 0) {
636 if (in.fd < 0) 636 if (in.fd < 0)
637 break; 637 break;
638 INTON; 638 INTON;
639 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR) 639 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR)
640 continue; 640 continue;
641 INTOFF; 641 INTOFF;
642 VTRACE(DBG_EXPAND, ("expbackq: read returns %d\n", i)); 642 VTRACE(DBG_EXPAND, ("expbackq: read returns %d\n", i));
643 if (i <= 0) 643 if (i <= 0)
644 break; 644 break;
645 p = buf; 645 p = buf;
646 in.nleft = i - 1; 646 in.nleft = i - 1;
647 } 647 }
648 lastc = *p++; 648 lastc = *p++;
649 if (lastc != '\0') { 649 if (lastc != '\0') {
650 if (lastc == '\n') /* don't save \n yet */ 650 if (lastc == '\n') /* don't save \n yet */
651 nnl++; /* it might be trailing */ 651 nnl++; /* it might be trailing */
652 else { 652 else {
653 /* 653 /*
654 * We have something other than \n 654 * We have something other than \n
655 * 655 *
656 * Before saving it, we need to insert 656 * Before saving it, we need to insert
657 * any \n's that we have just skipped. 657 * any \n's that we have just skipped.
658 */ 658 */
659 659
660 /* XXX 660 /* XXX
661 * this hack is just because our 661 * this hack is just because our
662 * CHECKSTRSPACE() is lazy, and only 662 * CHECKSTRSPACE() is lazy, and only
663 * ever grows the stack once, even 663 * ever grows the stack once, even
664 * if that does not allocate the space 664 * if that does not allocate the space
665 * we requested. ie: safe for small 665 * we requested. ie: safe for small
666 * requests, but not large ones. 666 * requests, but not large ones.
667 * FIXME someday... 667 * FIXME someday...
668 */ 668 */
669 if (nnl < 20) { 669 if (nnl < 20) {
670 CHECKSTRSPACE(nnl + 2, dest); 670 CHECKSTRSPACE(nnl + 2, dest);
671 while (nnl > 0) { 671 while (nnl > 0) {
672 nnl--; 672 nnl--;
673 USTPUTC('\n', dest); 673 USTPUTC('\n', dest);
674 } 674 }
675 } else { 675 } else {
676 /* The slower, safer, way */ 676 /* The slower, safer, way */
677 while (nnl > 0) { 677 while (nnl > 0) {
678 nnl--; 678 nnl--;
679 STPUTC('\n', dest); 679 STPUTC('\n', dest);
680 } 680 }
681 CHECKSTRSPACE(2, dest); 681 CHECKSTRSPACE(2, dest);
682 } 682 }
683 if ((quotes && quoted && NEEDESC(lastc)) || 683 if ((quotes && quoted && NEEDESC(lastc)) ||
684 ISCTL(lastc)) 684 ISCTL(lastc))
685 USTPUTC(CTLESC, dest); 685 USTPUTC(CTLESC, dest);
686 USTPUTC(lastc, dest); 686 USTPUTC(lastc, dest);
687 } 687 }
688 } 688 }
689 } 689 }
690 690
691 if (in.fd >= 0) 691 if (in.fd >= 0)
692 close(in.fd); 692 close(in.fd);
693 if (in.buf) 693 if (in.buf)
694 ckfree(in.buf); 694 ckfree(in.buf);
695 if (in.jp) 695 if (in.jp)
696 back_exitstatus = waitforjob(in.jp); 696 back_exitstatus = waitforjob(in.jp);
697 if (quoted == 0) 697 if (quoted == 0)
698 recordregion(startloc, dest - stackblock(), 0); 698 recordregion(startloc, dest - stackblock(), 0);
699 CTRACE(DBG_EXPAND, ("evalbackq: size=%d: \"%.*s\"\n", 699 CTRACE(DBG_EXPAND, ("evalbackq: size=%d: \"%.*s\"\n",
700 (int)((dest - stackblock()) - startloc), 700 (int)((dest - stackblock()) - startloc),
701 (int)((dest - stackblock()) - startloc), 701 (int)((dest - stackblock()) - startloc),
702 stackblock() + startloc)); 702 stackblock() + startloc));
703 703
704 expdest = dest; /* all done, expdest is all ours again */ 704 expdest = dest; /* all done, expdest is all ours again */
705 INTON; 705 INTON;
706} 706}
707 707
708 708
709STATIC int 709STATIC int
710subevalvar(const char *p, const char *str, int subtype, int startloc, 710subevalvar(const char *p, const char *str, int subtype, int startloc,
711 int varflags) 711 int varflags)
712{ 712{
713 char *startp; 713 char *startp;
714 int saveherefd = herefd; 714 int saveherefd = herefd;
715 struct nodelist *saveargbackq = argbackq; 715 struct nodelist *saveargbackq = argbackq;
716 int amount; 716 int amount;
717 717
718 herefd = -1; 718 herefd = -1;
719 VTRACE(DBG_EXPAND, ("subevalvar(%d) \"%.20s\" ${%.*s} sloc=%d vf=%x\n", 719 VTRACE(DBG_EXPAND, ("subevalvar(%d) \"%.20s\" ${%.*s} sloc=%d vf=%x\n",
720 subtype, p, p-str, str, startloc, varflags)); 720 subtype, p, p-str, str, startloc, varflags));
721 argstr(p, subtype == VSASSIGN ? EXP_VARTILDE : EXP_TILDE); 721 argstr(p, subtype == VSASSIGN ? EXP_VARTILDE : EXP_TILDE);
722 STACKSTRNUL(expdest); 722 STACKSTRNUL(expdest);
723 herefd = saveherefd; 723 herefd = saveherefd;
724 argbackq = saveargbackq; 724 argbackq = saveargbackq;
725 startp = stackblock() + startloc; 725 startp = stackblock() + startloc;
726 726
727 switch (subtype) { 727 switch (subtype) {
728 case VSASSIGN: 728 case VSASSIGN:
729 setvar(str, startp, 0); 729 setvar(str, startp, 0);
730 amount = startp - expdest; /* remove what argstr added */ 730 amount = startp - expdest; /* remove what argstr added */
731 STADJUST(amount, expdest); 731 STADJUST(amount, expdest);
732 varflags &= ~VSNUL; /*XXX Huh? What's that achieve? */ 732 varflags &= ~VSNUL; /*XXX Huh? What's that achieve? */
733 return 1; /* go back and eval var again */ 733 return 1; /* go back and eval var again */
734 734
735 case VSQUESTION: 735 case VSQUESTION:
736 if (*p != CTLENDVAR) { 736 if (*p != CTLENDVAR) {
737 outfmt(&errout, "%s\n", startp); 737 outfmt(&errout, "%s\n", startp);
738 error(NULL); 738 error(NULL);
739 } 739 }
740 error("%.*s: parameter %snot set", 740 error("%.*s: parameter %snot set",
741 (int)(p - str - 1), 741 (int)(p - str - 1),
742 str, (varflags & VSNUL) ? "null or " 742 str, (varflags & VSNUL) ? "null or "
743 : nullstr); 743 : nullstr);
744 /* NOTREACHED */ 744 /* NOTREACHED */
745 745
746 default: 746 default:
747 abort(); 747 abort();
748 } 748 }
749} 749}
750 750
751STATIC int 751STATIC int
752subevalvar_trim(const char *p, int strloc, int subtype, int startloc, 752subevalvar_trim(const char *p, int strloc, int subtype, int startloc,
753 int varflags, int quotes) 753 int varflags, int quotes)
754{ 754{
755 char *startp; 755 char *startp;
756 char *str; 756 char *str;
757 char *loc = NULL; 757 char *loc = NULL;
758 char *q; 758 char *q;
759 int c = 0; 759 int c = 0;
760 int saveherefd = herefd; 760 int saveherefd = herefd;
761 struct nodelist *saveargbackq = argbackq; 761 struct nodelist *saveargbackq = argbackq;
762 int amount; 762 int amount;
763 763
764 herefd = -1; 764 herefd = -1;
765 switch (subtype) { 765 switch (subtype) {
766 case VSTRIMLEFT: 766 case VSTRIMLEFT:
767 case VSTRIMLEFTMAX: 767 case VSTRIMLEFTMAX:
768 case VSTRIMRIGHT: 768 case VSTRIMRIGHT:
769 case VSTRIMRIGHTMAX: 769 case VSTRIMRIGHTMAX:
770 break; 770 break;
771 default: 771 default:
772 abort(); 772 abort();
773 break; 773 break;
774 } 774 }
775 775
776 VTRACE(DBG_EXPAND, 776 VTRACE(DBG_EXPAND,
777 ("subevalvar_trim(\"%.9s\", STR@%d, SUBT=%d, start@%d, vf=%x, q=%x)\n", 777 ("subevalvar_trim(\"%.9s\", STR@%d, SUBT=%d, start@%d, vf=%x, q=%x)\n",
778 p, strloc, subtype, startloc, varflags, quotes)); 778 p, strloc, subtype, startloc, varflags, quotes));
779 779
780 argstr(p, (varflags & (VSQUOTE|VSPATQ)) == VSQUOTE ? 0 : EXP_CASE); 780 argstr(p, (varflags & (VSQUOTE|VSPATQ)) == VSQUOTE ? 0 : EXP_CASE);
781 STACKSTRNUL(expdest); 781 STACKSTRNUL(expdest);
782 herefd = saveherefd; 782 herefd = saveherefd;
783 argbackq = saveargbackq; 783 argbackq = saveargbackq;
784 startp = stackblock() + startloc; 784 startp = stackblock() + startloc;
785 str = stackblock() + strloc; 785 str = stackblock() + strloc;
786 786
787 switch (subtype) { 787 switch (subtype) {
788 788
789 case VSTRIMLEFT: 789 case VSTRIMLEFT:
790 for (loc = startp; loc < str; loc++) { 790 for (loc = startp; loc < str; loc++) {
791 c = *loc; 791 c = *loc;
792 *loc = '\0'; 792 *loc = '\0';
793 if (patmatch(str, startp, quotes)) 793 if (patmatch(str, startp, quotes))
794 goto recordleft; 794 goto recordleft;
795 *loc = c; 795 *loc = c;
796 if (quotes && *loc == CTLESC) 796 if (quotes && *loc == CTLESC)
797 loc++; 797 loc++;
798 } 798 }
799 return 0; 799 return 0;
800 800
801 case VSTRIMLEFTMAX: 801 case VSTRIMLEFTMAX:
802 for (loc = str - 1; loc >= startp;) { 802 for (loc = str - 1; loc >= startp;) {
803 c = *loc; 803 c = *loc;
804 *loc = '\0'; 804 *loc = '\0';
805 if (patmatch(str, startp, quotes)) 805 if (patmatch(str, startp, quotes))
806 goto recordleft; 806 goto recordleft;
807 *loc = c; 807 *loc = c;
808 loc--; 808 loc--;
809 if (quotes && loc > startp && 809 if (quotes && loc > startp &&
810 *(loc - 1) == CTLESC) { 810 *(loc - 1) == CTLESC) {
811 for (q = startp; q < loc; q++) 811 for (q = startp; q < loc; q++)
812 if (*q == CTLESC) 812 if (*q == CTLESC)
813 q++; 813 q++;
814 if (q > loc) 814 if (q > loc)
815 loc--; 815 loc--;
816 } 816 }
817 } 817 }
818 return 0; 818 return 0;
819 819
820 case VSTRIMRIGHT: 820 case VSTRIMRIGHT:
821 for (loc = str - 1; loc >= startp;) { 821 for (loc = str - 1; loc >= startp;) {
822 if (patmatch(str, loc, quotes)) 822 if (patmatch(str, loc, quotes))
823 goto recordright; 823 goto recordright;
824 loc--; 824 loc--;
825 if (quotes && loc > startp && 825 if (quotes && loc > startp &&
826 *(loc - 1) == CTLESC) { 826 *(loc - 1) == CTLESC) {
827 for (q = startp; q < loc; q++) 827 for (q = startp; q < loc; q++)
828 if (*q == CTLESC) 828 if (*q == CTLESC)
829 q++; 829 q++;
830 if (q > loc) 830 if (q > loc)
831 loc--; 831 loc--;
832 } 832 }
833 } 833 }
834 return 0; 834 return 0;
835 835
836 case VSTRIMRIGHTMAX: 836 case VSTRIMRIGHTMAX:
837 for (loc = startp; loc < str - 1; loc++) { 837 for (loc = startp; loc < str - 1; loc++) {
838 if (patmatch(str, loc, quotes)) 838 if (patmatch(str, loc, quotes))
839 goto recordright; 839 goto recordright;
840 if (quotes && *loc == CTLESC) 840 if (quotes && *loc == CTLESC)
841 loc++; 841 loc++;
842 } 842 }
843 return 0; 843 return 0;
844 844
845 default: 845 default:
846 abort(); 846 abort();
847 } 847 }
848 848
849 recordleft: 849 recordleft:
850 *loc = c; 850 *loc = c;
851 amount = ((str - 1) - (loc - startp)) - expdest; 851 amount = ((str - 1) - (loc - startp)) - expdest;
852 STADJUST(amount, expdest); 852 STADJUST(amount, expdest);
853 while (loc != str - 1) 853 while (loc != str - 1)
854 *startp++ = *loc++; 854 *startp++ = *loc++;
855 return 1; 855 return 1;
856 856
857 recordright: 857 recordright:
858 amount = loc - expdest; 858 amount = loc - expdest;
859 STADJUST(amount, expdest); 859 STADJUST(amount, expdest);
860 STPUTC('\0', expdest); 860 STPUTC('\0', expdest);
861 STADJUST(-1, expdest); 861 STADJUST(-1, expdest);
862 return 1; 862 return 1;
863} 863}
864 864
865 865
866/* 866/*
867 * Expand a variable, and return a pointer to the next character in the 867 * Expand a variable, and return a pointer to the next character in the
868 * input string. 868 * input string.
869 */ 869 */
870 870
871STATIC const char * 871STATIC const char *
872evalvar(const char *p, int flag) 872evalvar(const char *p, int flag)
873{ 873{
874 int subtype; 874 int subtype;
875 int varflags; 875 int varflags;
876 const char *var; 876 const char *var;
877 char *val; 877 char *val;
878 int patloc; 878 int patloc;
879 int c; 879 int c;
880 int set; 880 int set;
881 int special; 881 int special;
882 int startloc; 882 int startloc;
883 int varlen; 883 int varlen;
884 int apply_ifs; 884 int apply_ifs;
885 const int quotes = flag & EXP_QNEEDED; 885 const int quotes = flag & EXP_QNEEDED;
886 886
887 varflags = (unsigned char)*p++; 887 varflags = (unsigned char)*p++;
888 subtype = varflags & VSTYPE; 888 subtype = varflags & VSTYPE;
889 var = p; 889 var = p;
890 special = !is_name(*p); 890 special = !is_name(*p);
891 p = strchr(p, '=') + 1; 891 p = strchr(p, '=') + 1;
892 892
893 CTRACE(DBG_EXPAND, 893 CTRACE(DBG_EXPAND,
894 ("evalvar \"%.*s\", flag=%#X quotes=%#X vf=%#X subtype=%X\n", 894 ("evalvar \"%.*s\", flag=%#X quotes=%#X vf=%#X subtype=%X\n",
895 p - var - 1, var, flag, quotes, varflags, subtype)); 895 p - var - 1, var, flag, quotes, varflags, subtype));
896 896
897 again: /* jump here after setting a variable with ${var=text} */ 897 again: /* jump here after setting a variable with ${var=text} */
898 if (varflags & VSLINENO) { 898 if (varflags & VSLINENO) {
899 if (line_num.flags & VUNSET) { 899 if (line_num.flags & VUNSET) {
900 set = 0; 900 set = 0;
901 val = NULL; 901 val = NULL;
902 } else { 902 } else {
903 set = 1; 903 set = 1;
904 special = p - var; 904 special = p - var;
905 val = NULL; 905 val = NULL;
906 } 906 }
907 } else if (special) { 907 } else if (special) {
908 set = varisset(var, varflags & VSNUL); 908 set = varisset(var, varflags & VSNUL);
909 val = NULL; 909 val = NULL;
910 if (!set && *var == '@') 910 if (!set && *var == '@')
911 empty_dollar_at = 1; 911 empty_dollar_at = 1;
912 } else { 912 } else {
913 val = lookupvar(var); 913 val = lookupvar(var);
914 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { 914 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
915 val = NULL; 915 val = NULL;
916 set = 0; 916 set = 0;
917 } else 917 } else
918 set = 1; 918 set = 1;
919 } 919 }
920 920
921 varlen = 0; 921 varlen = 0;
922 startloc = expdest - stackblock(); 922 startloc = expdest - stackblock();
923 923
924 if (!set && uflag && *var != '@' && *var != '*') { 924 if (!set && uflag && *var != '@' && *var != '*') {
925 switch (subtype) { 925 switch (subtype) {
926 case VSNORMAL: 926 case VSNORMAL:
927 case VSTRIMLEFT: 927 case VSTRIMLEFT:
928 case VSTRIMLEFTMAX: 928 case VSTRIMLEFTMAX:
929 case VSTRIMRIGHT: 929 case VSTRIMRIGHT:
930 case VSTRIMRIGHTMAX: 930 case VSTRIMRIGHTMAX:
931 case VSLENGTH: 931 case VSLENGTH:
932 error("%.*s: parameter not set", 932 error("%.*s: parameter not set",
933 (int)(p - var - 1), var); 933 (int)(p - var - 1), var);
934 /* NOTREACHED */ 934 /* NOTREACHED */
935 } 935 }
936 } 936 }
937 937
938#if 0 /* no longer need this $@ evil ... */ 938#if 0 /* no longer need this $@ evil ... */
939 if (!set && subtype != VSPLUS && special && *var == '@') 939 if (!set && subtype != VSPLUS && special && *var == '@')
940 if (startloc > 0 && expdest[-1] == CTLQUOTEMARK) 940 if (startloc > 0 && expdest[-1] == CTLQUOTEMARK)
941 expdest--, startloc--; 941 expdest--, startloc--;
942#endif 942#endif
943 943
944 if (set && subtype != VSPLUS) { 944 if (set && subtype != VSPLUS) {
945 /* insert the value of the variable */ 945 /* insert the value of the variable */
946 if (special) { 946 if (special) {
947 if (varflags & VSLINENO) { 947 if (varflags & VSLINENO) {
948 /* 948 /*
949 * The LINENO hack (expansion part) 949 * The LINENO hack (expansion part)
950 */ 950 */
951 while (--special > 0) { 951 while (--special > 0) {
952/* not needed, it is a number... 952/* not needed, it is a number...
953 if (quotes && NEEDESC(*var)) 953 if (quotes && NEEDESC(*var))
954 STPUTC(CTLESC, expdest); 954 STPUTC(CTLESC, expdest);
955*/ 955*/
956 STPUTC(*var++, expdest); 956 STPUTC(*var++, expdest);
957 } 957 }
958 } else 958 } else
959 varvalue(var, varflags&VSQUOTE, subtype, flag); 959 varvalue(var, varflags&VSQUOTE, subtype, flag);
960 if (subtype == VSLENGTH) { 960 if (subtype == VSLENGTH) {
961 varlen = expdest - stackblock() - startloc; 961 varlen = expdest - stackblock() - startloc;
962 STADJUST(-varlen, expdest); 962 STADJUST(-varlen, expdest);
963 } 963 }
964 } else { 964 } else {
965 965
966 if (subtype == VSLENGTH) { 966 if (subtype == VSLENGTH) {
967 for (; *val; val++) 967 for (; *val; val++)
968 varlen++; 968 varlen++;
969 } else if (quotes && varflags & VSQUOTE) { 969 } else if (quotes && varflags & VSQUOTE) {
970 /* 970 /*
971 * If we are going to look for magic in the 971 * If we are going to look for magic in the
972 * value (quotes is set) and the expansion 972 * value (quotes is set) and the expansion
973 * occurs inside "" (VSQUOTE) then any char 973 * occurs inside "" (VSQUOTE) then any char
974 * that has any potential special meaning 974 * that has any potential special meaning
975 * needs to have that meaning suppressed, 975 * needs to have that meaning suppressed,
976 * so supply a CTLESC prefix for it. 976 * so supply a CTLESC prefix for it.
977 */ 977 */
978 for (; (c = *val) != '\0'; val++) { 978 for (; (c = *val) != '\0'; val++) {
979 if (NEEDESC(c)) 979 if (NEEDESC(c))
980 STPUTC(CTLESC, expdest); 980 STPUTC(CTLESC, expdest);
981 STPUTC(c, expdest); 981 STPUTC(c, expdest);
982 } 982 }
983 } else { 983 } else {
984 /* 984 /*
985 * We are going to rmescapes() later, 985 * We are going to rmescapes() later,
986 * so make sure that any data char that 986 * so make sure that any data char that
987 * might be mistaken for one of our CTLxxx 987 * might be mistaken for one of our CTLxxx
988 * magic chars is protected ... always. 988 * magic chars is protected ... always.
989 */ 989 */
990 for (; (c = *val) != '\0'; val++) { 990 for (; (c = *val) != '\0'; val++) {
991 if (ISCTL(c)) 991 if (ISCTL(c))
992 STPUTC(CTLESC, expdest); 992 STPUTC(CTLESC, expdest);
993 STPUTC(c, expdest); 993 STPUTC(c, expdest);
994 } 994 }
995 } 995 }
996 } 996 }
997 } 997 }
998 998
999 999
1000 if (varflags & VSQUOTE) { 1000 if (varflags & VSQUOTE) {
1001 if (*var == '@' && shellparam.nparam != 1) 1001 if (*var == '@' && shellparam.nparam != 1)
1002 apply_ifs = 1; 1002 apply_ifs = 1;
1003 else { 1003 else {
1004 /* 1004 /*
1005 * Mark so that we don't apply IFS if we recurse through 1005 * Mark so that we don't apply IFS if we recurse through
1006 * here expanding $bar from "${foo-$bar}". 1006 * here expanding $bar from "${foo-$bar}".
1007 */ 1007 */
1008 flag |= EXP_IN_QUOTES; 1008 flag |= EXP_IN_QUOTES;
1009 apply_ifs = 0; 1009 apply_ifs = 0;
1010 } 1010 }
1011 } else if (flag & EXP_IN_QUOTES) { 1011 } else if (flag & EXP_IN_QUOTES) {
1012 apply_ifs = 0; 1012 apply_ifs = 0;
1013 } else 1013 } else
1014 apply_ifs = 1; 1014 apply_ifs = 1;
1015 1015
1016 switch (subtype) { 1016 switch (subtype) {
1017 case VSLENGTH: 1017 case VSLENGTH:
1018 expdest = cvtnum(varlen, expdest); 1018 expdest = cvtnum(varlen, expdest);
1019 break; 1019 break;
1020 1020
1021 case VSNORMAL: 1021 case VSNORMAL:
1022 break; 1022 break;
1023 1023
1024 case VSPLUS: 1024 case VSPLUS:
1025 set = !set; 1025 set = !set;
1026 /* FALLTHROUGH */ 1026 /* FALLTHROUGH */
1027 case VSMINUS: 1027 case VSMINUS:
1028 if (!set) { 1028 if (!set) {
1029 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); 1029 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
1030 /* 1030 /*
1031 * ${x-a b c} doesn't get split, but removing the 1031 * ${x-a b c} doesn't get split, but removing the
1032 * 'apply_ifs = 0' apparently breaks ${1+"$@"}.. 1032 * 'apply_ifs = 0' apparently breaks ${1+"$@"}..
1033 * ${x-'a b' c} should generate 2 args. 1033 * ${x-'a b' c} should generate 2 args.
1034 */ 1034 */
1035 if (*p != CTLENDVAR) 1035 if (*p != CTLENDVAR)
1036 /* We should have marked stuff already */ 1036 /* We should have marked stuff already */
1037 apply_ifs = 0; 1037 apply_ifs = 0;
1038 } 1038 }
1039 break; 1039 break;
1040 1040
1041 case VSTRIMLEFT: 1041 case VSTRIMLEFT:
1042 case VSTRIMLEFTMAX: 1042 case VSTRIMLEFTMAX:
1043 case VSTRIMRIGHT: 1043 case VSTRIMRIGHT:
1044 case VSTRIMRIGHTMAX: 1044 case VSTRIMRIGHTMAX:
1045 if (!set) { 1045 if (!set) {
1046 set = 1; /* allow argbackq to be advanced if needed */ 1046 set = 1; /* allow argbackq to be advanced if needed */
1047 break; 1047 break;
1048 } 1048 }
1049 /* 1049 /*
1050 * Terminate the string and start recording the pattern 1050 * Terminate the string and start recording the pattern
1051 * right after it 1051 * right after it
1052 */ 1052 */
1053 STPUTC('\0', expdest); 1053 STPUTC('\0', expdest);
1054 patloc = expdest - stackblock(); 1054 patloc = expdest - stackblock();
1055 if (subevalvar_trim(p, patloc, subtype, startloc, varflags, 1055 if (subevalvar_trim(p, patloc, subtype, startloc, varflags,
1056 quotes) == 0) { 1056 quotes) == 0) {
1057 int amount = (expdest - stackblock() - patloc) + 1; 1057 int amount = (expdest - stackblock() - patloc) + 1;
1058 STADJUST(-amount, expdest); 1058 STADJUST(-amount, expdest);
1059 } 1059 }
1060 /* Remove any recorded regions beyond start of variable */ 1060 /* Remove any recorded regions beyond start of variable */
1061 removerecordregions(startloc); 1061 removerecordregions(startloc);
1062 apply_ifs = 1; 1062 apply_ifs = 1;
1063 break; 1063 break;
1064 1064
1065 case VSASSIGN: 1065 case VSASSIGN:
1066 case VSQUESTION: 1066 case VSQUESTION:
1067 if (set) 1067 if (set)
1068 break; 1068 break;
1069 if (subevalvar(p, var, subtype, startloc, varflags)) { 1069 if (subevalvar(p, var, subtype, startloc, varflags)) {
1070 /* if subevalvar() returns, it always returns 1 */ 1070 /* if subevalvar() returns, it always returns 1 */
1071 1071
1072 varflags &= ~VSNUL; 1072 varflags &= ~VSNUL;
1073 /* 1073 /*
1074 * Remove any recorded regions beyond 1074 * Remove any recorded regions beyond
1075 * start of variable 1075 * start of variable
1076 */ 1076 */
1077 removerecordregions(startloc); 1077 removerecordregions(startloc);
1078 goto again; 1078 goto again;
1079 } 1079 }
1080 apply_ifs = 0; /* never executed */ 1080 apply_ifs = 0; /* never executed */
1081 break; 1081 break;
1082 1082
1083 default: 1083 default:
1084 abort(); 1084 abort();
1085 } 1085 }
1086 1086
1087 if (apply_ifs) 1087 if (apply_ifs)
1088 recordregion(startloc, expdest - stackblock(), 1088 recordregion(startloc, expdest - stackblock(),
1089 varflags & VSQUOTE); 1089 varflags & VSQUOTE);
1090 1090
1091 if (subtype != VSNORMAL) { /* skip to end of alternative */ 1091 if (subtype != VSNORMAL) { /* skip to end of alternative */
1092 int nesting = 1; 1092 int nesting = 1;
1093 for (;;) { 1093 for (;;) {
1094 if ((c = *p++) == CTLESC) 1094 if ((c = *p++) == CTLESC)
1095 p++; 1095 p++;
1096 else if (c == CTLNONL) 1096 else if (c == CTLNONL)
1097 ; 1097 ;
1098 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 1098 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
1099 if (set) 1099 if (set)
1100 argbackq = argbackq->next; 1100 argbackq = argbackq->next;
1101 } else if (c == CTLVAR) { 1101 } else if (c == CTLVAR) {
1102 if ((*p++ & VSTYPE) != VSNORMAL) 1102 if ((*p++ & VSTYPE) != VSNORMAL)
1103 nesting++; 1103 nesting++;
1104 } else if (c == CTLENDVAR) { 1104 } else if (c == CTLENDVAR) {
1105 if (--nesting == 0) 1105 if (--nesting == 0)
1106 break; 1106 break;
1107 } 1107 }
1108 } 1108 }
1109 } 1109 }
1110 return p; 1110 return p;
1111} 1111}
1112 1112
1113 1113
1114 1114
1115/* 1115/*
1116 * Test whether a special parameter is set. 1116 * Test whether a special parameter is set.
1117 */ 1117 */
1118 1118
1119STATIC int 1119STATIC int
1120varisset(const char *name, int nulok) 1120varisset(const char *name, int nulok)
1121{ 1121{
1122 if (*name == '!') 1122 if (*name == '!')
1123 return backgndpid != -1; 1123 return backgndpid != -1;
1124 else if (*name == '@' || *name == '*') { 1124 else if (*name == '@' || *name == '*') {
1125 if (*shellparam.p == NULL) 1125 if (*shellparam.p == NULL)
1126 return 0; 1126 return 0;
1127 1127
1128 if (nulok) { 1128 if (nulok) {
1129 char **av; 1129 char **av;
1130 1130
1131 for (av = shellparam.p; *av; av++) 1131 for (av = shellparam.p; *av; av++)
1132 if (**av != '\0') 1132 if (**av != '\0')
1133 return 1; 1133 return 1;
1134 return 0; 1134 return 0;
1135 } 1135 }
1136 } else if (is_digit(*name)) { 1136 } else if (is_digit(*name)) {
1137 char *ap; 1137 char *ap;
1138 long num; 1138 long num;
1139 1139
1140 /* 1140 /*
1141 * handle overflow sensibly (the *ap tests should never fail) 1141 * handle overflow sensibly (the *ap tests should never fail)
1142 */ 1142 */
1143 errno = 0; 1143 errno = 0;
1144 num = strtol(name, &ap, 10); 1144 num = strtol(name, &ap, 10);
1145 if (errno != 0 || (*ap != '\0' && *ap != '=')) 1145 if (errno != 0 || (*ap != '\0' && *ap != '='))
1146 return 0; 1146 return 0;
1147 1147
1148 if (num == 0) 1148 if (num == 0)
1149 ap = arg0; 1149 ap = arg0;
1150 else if (num > shellparam.nparam) 1150 else if (num > shellparam.nparam)
1151 return 0; 1151 return 0;
1152 else 1152 else
1153 ap = shellparam.p[num - 1]; 1153 ap = shellparam.p[num - 1];
1154 1154
1155 if (nulok && (ap == NULL || *ap == '\0')) 1155 if (nulok && (ap == NULL || *ap == '\0'))
1156 return 0; 1156 return 0;
1157 } 1157 }
1158 return 1; 1158 return 1;
1159} 1159}
1160 1160
1161 1161
1162 1162
1163/* 1163/*
1164 * Add the value of a specialized variable to the stack string. 1164 * Add the value of a specialized variable to the stack string.
1165 */ 1165 */
1166 1166
1167STATIC void 1167STATIC void
1168varvalue(const char *name, int quoted, int subtype, int flag) 1168varvalue(const char *name, int quoted, int subtype, int flag)
1169{ 1169{
1170 int num; 1170 int num;
1171 char *p; 1171 char *p;
1172 int i; 1172 int i;
1173 int sep; 1173 int sep;
1174 char **ap; 1174 char **ap;
1175#ifdef DEBUG 1175#ifdef DEBUG
1176 char *start = expdest; 1176 char *start = expdest;
1177#endif 1177#endif
1178 1178
1179 VTRACE(DBG_EXPAND, ("varvalue(%c%s, sub=%d, fl=%#x)", *name, 1179 VTRACE(DBG_EXPAND, ("varvalue(%c%s, sub=%d, fl=%#x)", *name,
1180 quoted ? ", quoted" : "", subtype, flag)); 1180 quoted ? ", quoted" : "", subtype, flag));
1181 1181
1182 if (subtype == VSLENGTH) /* no magic required ... */ 1182 if (subtype == VSLENGTH) /* no magic required ... */
1183 flag &= ~EXP_FULL; 1183 flag &= ~EXP_FULL;
1184 1184
1185#define STRTODEST(p) \ 1185#define STRTODEST(p) \
1186 do {\ 1186 do {\
1187 if ((flag & EXP_QNEEDED) && quoted) { \ 1187 if ((flag & EXP_QNEEDED) && quoted) { \
1188 while (*p) { \ 1188 while (*p) { \
1189 if (NEEDESC(*p)) \ 1189 if (NEEDESC(*p)) \
1190 STPUTC(CTLESC, expdest); \ 1190 STPUTC(CTLESC, expdest); \
1191 STPUTC(*p++, expdest); \ 1191 STPUTC(*p++, expdest); \
1192 } \ 1192 } \
1193 } else \ 1193 } else \
1194 while (*p) { \ 1194 while (*p) { \
1195 if (ISCTL(*p)) \ 1195 if (ISCTL(*p)) \
1196 STPUTC(CTLESC, expdest); \ 1196 STPUTC(CTLESC, expdest); \
1197 STPUTC(*p++, expdest); \ 1197 STPUTC(*p++, expdest); \
1198 } \ 1198 } \
1199 } while (0) 1199 } while (0)
1200 1200
1201 1201
1202 switch (*name) { 1202 switch (*name) {
1203 case '$': 1203 case '$':
1204 num = rootpid; 1204 num = rootpid;
1205 break; 1205 break;
1206 case '?': 1206 case '?':
1207 num = exitstatus; 1207 num = exitstatus;
1208 break; 1208 break;
1209 case '#': 1209 case '#':
1210 num = shellparam.nparam; 1210 num = shellparam.nparam;
1211 break; 1211 break;
1212 case '!': 1212 case '!':
1213 num = backgndpid; 1213 num = backgndpid;
1214 break; 1214 break;
1215 case '-': 1215 case '-':
1216 for (i = 0; i < option_flags; i++) { 1216 for (i = 0; i < option_flags; i++) {
1217 if (optlist[optorder[i]].val) 1217 if (optlist[optorder[i]].val)
1218 STPUTC(optlist[optorder[i]].letter, expdest); 1218 STPUTC(optlist[optorder[i]].letter, expdest);
1219 } 1219 }
1220 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start)); 1220 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
1221 return; 1221 return;
1222 case '@': 1222 case '@':
1223 if (flag & EXP_SPLIT && quoted) { 1223 if (flag & EXP_SPLIT && quoted) {
1224 VTRACE(DBG_EXPAND, (": $@ split (%d)\n", 1224 VTRACE(DBG_EXPAND, (": $@ split (%d)\n",
1225 shellparam.nparam)); 1225 shellparam.nparam));
1226#if 0 1226#if 0
1227 /* GROSS HACK */ 1227 /* GROSS HACK */
1228 if (shellparam.nparam == 0 && 1228 if (shellparam.nparam == 0 &&
1229 expdest[-1] == CTLQUOTEMARK) 1229 expdest[-1] == CTLQUOTEMARK)
1230 expdest--; 1230 expdest--;
1231 /* KCAH SSORG */ 1231 /* KCAH SSORG */
1232#endif 1232#endif
1233 if (shellparam.nparam == 0) 1233 if (shellparam.nparam == 0)
1234 empty_dollar_at = 1; 1234 empty_dollar_at = 1;
1235 1235
1236 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 1236 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
1237 if (*p == '\0') { 1237 if (*p == '\0') {
1238 /* retain an explicit null string */ 1238 /* retain an explicit null string */
1239 STPUTC(CTLQUOTEMARK, expdest); 1239 STPUTC(CTLQUOTEMARK, expdest);
1240 STPUTC(CTLQUOTEEND, expdest); 1240 STPUTC(CTLQUOTEEND, expdest);
1241 } else 1241 } else
1242 STRTODEST(p); 1242 STRTODEST(p);
1243 if (*ap) 1243 if (*ap)
1244 /* A NUL separates args inside "" */ 1244 /* A NUL separates args inside "" */
1245 STPUTC('\0', expdest); 1245 STPUTC('\0', expdest);
1246 } 1246 }
1247 return; 1247 return;
1248 } 1248 }
1249 /* fall through */ 1249 /* fall through */
1250 case '*': 1250 case '*':
1251 sep = ifsval()[0]; 1251 sep = ifsval()[0];
1252 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 1252 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
1253 STRTODEST(p); 1253 STRTODEST(p);
1254 if (!*ap) 1254 if (!*ap)
1255 break; 1255 break;
1256 if (sep) { 1256 if (sep) {
1257 if (quoted && (flag & EXP_QNEEDED) && 1257 if (quoted && (flag & EXP_QNEEDED) &&
1258 NEEDESC(sep)) 1258 NEEDESC(sep))
1259 STPUTC(CTLESC, expdest); 1259 STPUTC(CTLESC, expdest);
1260 STPUTC(sep, expdest); 1260 STPUTC(sep, expdest);
1261 } else 1261 } else
1262 if ((flag & (EXP_SPLIT|EXP_IN_QUOTES)) == EXP_SPLIT 1262 if ((flag & (EXP_SPLIT|EXP_IN_QUOTES)) == EXP_SPLIT
1263 && !quoted && **ap != '\0') 1263 && !quoted && **ap != '\0')
1264 STPUTC('\0', expdest); 1264 STPUTC('\0', expdest);
1265 } 1265 }
1266 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start)); 1266 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
1267 return; 1267 return;
1268 default: 1268 default:
1269 if (is_digit(*name)) { 1269 if (is_digit(*name)) {
1270 long lnum; 1270 long lnum;
1271 1271
1272 errno = 0; 1272 errno = 0;
1273 lnum = strtol(name, &p, 10); 1273 lnum = strtol(name, &p, 10);
1274 if (errno != 0 || (*p != '\0' && *p != '=')) 1274 if (errno != 0 || (*p != '\0' && *p != '='))
1275 return; 1275 return;
1276 1276
1277 if (lnum == 0) 1277 if (lnum == 0)
1278 p = arg0; 1278 p = arg0;
1279 else if (lnum > 0 && lnum <= shellparam.nparam) 1279 else if (lnum > 0 && lnum <= shellparam.nparam)
1280 p = shellparam.p[lnum - 1]; 1280 p = shellparam.p[lnum - 1];
1281 else 1281 else
1282 return; 1282 return;
1283 STRTODEST(p); 1283 STRTODEST(p);
1284 } 1284 }
1285 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start)); 1285 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
1286 return; 1286 return;
1287 } 1287 }
1288 /* 1288 /*
1289 * only the specials with an int value arrive here 1289 * only the specials with an int value arrive here
1290 */ 1290 */
1291 VTRACE(DBG_EXPAND, ("(%d)", num)); 1291 VTRACE(DBG_EXPAND, ("(%d)", num));
1292 expdest = cvtnum(num, expdest); 1292 expdest = cvtnum(num, expdest);
1293 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start)); 1293 VTRACE(DBG_EXPAND, (": %.*s\n", expdest-start, start));
1294} 1294}
1295 1295
1296 1296
1297 1297
1298/* 1298/*
1299 * Record the fact that we have to scan this region of the 1299 * Record the fact that we have to scan this region of the
1300 * string for IFS characters. 1300 * string for IFS characters.
1301 */ 1301 */
1302 1302
1303STATIC void 1303STATIC void
1304recordregion(int start, int end, int inquotes) 1304recordregion(int start, int end, int inquotes)
1305{ 1305{
1306 struct ifsregion *ifsp; 1306 struct ifsregion *ifsp;
1307 1307
1308 VTRACE(DBG_EXPAND, ("recordregion(%d,%d,%d)\n", start, end, inquotes)); 1308 VTRACE(DBG_EXPAND, ("recordregion(%d,%d,%d)\n", start, end, inquotes));
1309 if (ifslastp == NULL) { 1309 if (ifslastp == NULL) {
1310 ifsp = &ifsfirst; 1310 ifsp = &ifsfirst;
1311 } else { 1311 } else {
1312 if (ifslastp->endoff == start 1312 if (ifslastp->endoff == start
1313 && ifslastp->inquotes == inquotes) { 1313 && ifslastp->inquotes == inquotes) {
1314 /* extend previous area */ 1314 /* extend previous area */
1315 ifslastp->endoff = end; 1315 ifslastp->endoff = end;
1316 return; 1316 return;
1317 } 1317 }
1318 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 1318 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
1319 ifslastp->next = ifsp; 1319 ifslastp->next = ifsp;
1320 } 1320 }
1321 ifslastp = ifsp; 1321 ifslastp = ifsp;
1322 ifslastp->next = NULL; 1322 ifslastp->next = NULL;
1323 ifslastp->begoff = start; 1323 ifslastp->begoff = start;
1324 ifslastp->endoff = end; 1324 ifslastp->endoff = end;
1325 ifslastp->inquotes = inquotes; 1325 ifslastp->inquotes = inquotes;
1326} 1326}
1327 1327
1328 1328
1329 1329
1330/* 1330/*
1331 * Break the argument string into pieces based upon IFS and add the 1331 * Break the argument string into pieces based upon IFS and add the
1332 * strings to the argument list. The regions of the string to be 1332 * strings to the argument list. The regions of the string to be
1333 * searched for IFS characters have been stored by recordregion. 1333 * searched for IFS characters have been stored by recordregion.
1334 */ 1334 */
1335STATIC void 1335STATIC void
1336ifsbreakup(char *string, struct arglist *arglist) 1336ifsbreakup(char *string, struct arglist *arglist)
1337{ 1337{
1338 struct ifsregion *ifsp; 1338 struct ifsregion *ifsp;
1339 struct strlist *sp; 1339 struct strlist *sp;
1340 char *start; 1340 char *start;
1341 char *p; 1341 char *p;
1342 char *q; 1342 char *q;
1343 const char *ifs; 1343 const char *ifs;
1344 const char *ifsspc; 1344 const char *ifsspc;
1345 int had_param_ch = 0; 1345 int had_param_ch = 0;
1346 1346
1347 start = string; 1347 start = string;
1348 1348
1349 VTRACE(DBG_EXPAND, ("ifsbreakup(\"%s\")", string)); /* misses \0's */ 1349 VTRACE(DBG_EXPAND, ("ifsbreakup(\"%s\")", string)); /* misses \0's */
1350 if (ifslastp == NULL) { 1350 if (ifslastp == NULL) {
1351 /* Return entire argument, IFS doesn't apply to any of it */ 1351 /* Return entire argument, IFS doesn't apply to any of it */
1352 VTRACE(DBG_EXPAND, ("no regions\n", string)); 1352 VTRACE(DBG_EXPAND, ("no regions\n", string));
1353 sp = stalloc(sizeof(*sp)); 1353 sp = stalloc(sizeof(*sp));
1354 sp->text = start; 1354 sp->text = start;
1355 *arglist->lastp = sp; 1355 *arglist->lastp = sp;
1356 arglist->lastp = &sp->next; 1356 arglist->lastp = &sp->next;
1357 return; 1357 return;
1358 } 1358 }
1359 1359
1360 ifs = ifsval(); 1360 ifs = ifsval();
1361 1361
1362 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) { 1362 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1363 p = string + ifsp->begoff; 1363 p = string + ifsp->begoff;
1364 VTRACE(DBG_EXPAND, (" !%.*s!(%d)", ifsp->endoff-ifsp->begoff, 1364 VTRACE(DBG_EXPAND, (" !%.*s!(%d)", ifsp->endoff-ifsp->begoff,
1365 p, ifsp->endoff-ifsp->begoff)); 1365 p, ifsp->endoff-ifsp->begoff));
1366 while (p < string + ifsp->endoff) { 1366 while (p < string + ifsp->endoff) {
1367 had_param_ch = 1; 1367 had_param_ch = 1;
1368 q = p; 1368 q = p;
1369 if (IS_BORING(*p)) { 1369 if (IS_BORING(*p)) {
1370 p++; 1370 p++;
1371 continue; 1371 continue;
1372 } 1372 }
1373 if (*p == CTLESC) 1373 if (*p == CTLESC)
1374 p++; 1374 p++;
1375 if (ifsp->inquotes) { 1375 if (ifsp->inquotes) {
1376 /* Only NULs (should be from "$@") end args */ 1376 /* Only NULs (should be from "$@") end args */
1377 if (*p != 0) { 1377 if (*p != 0) {
1378 p++; 1378 p++;
1379 continue; 1379 continue;
1380 } 1380 }
1381 ifsspc = NULL; 1381 ifsspc = NULL;
1382 VTRACE(DBG_EXPAND, (" \\0 nxt:\"%s\" ", p)); 1382 VTRACE(DBG_EXPAND, (" \\0 nxt:\"%s\" ", p));
1383 } else { 1383 } else {
1384 if (!strchr(ifs, *p)) { 1384 if (!strchr(ifs, *p)) {
1385 p++; 1385 p++;
1386 continue; 1386 continue;
1387 } 1387 }
1388 had_param_ch = 0; 1388 had_param_ch = 0;
1389 ifsspc = strchr(" \t\n", *p); 1389 ifsspc = strchr(" \t\n", *p);
1390 1390
1391 /* Ignore IFS whitespace at start */ 1391 /* Ignore IFS whitespace at start */
1392 if (q == start && ifsspc != NULL) { 1392 if (q == start && ifsspc != NULL) {
1393 p++; 1393 p++;
1394 start = p; 1394 start = p;
1395 continue; 1395 continue;
1396 } 1396 }
1397 } 1397 }
1398 1398
1399 /* Save this argument... */ 1399 /* Save this argument... */
1400 *q = '\0'; 1400 *q = '\0';
1401 VTRACE(DBG_EXPAND, ("<%s>", start)); 1401 VTRACE(DBG_EXPAND, ("<%s>", start));
1402 sp = stalloc(sizeof(*sp)); 1402 sp = stalloc(sizeof(*sp));
1403 sp->text = start; 1403 sp->text = start;
1404 *arglist->lastp = sp; 1404 *arglist->lastp = sp;
1405 arglist->lastp = &sp->next; 1405 arglist->lastp = &sp->next;
1406 p++; 1406 p++;
1407 1407
1408 if (ifsspc != NULL) { 1408 if (ifsspc != NULL) {
1409 /* Ignore further trailing IFS whitespace */ 1409 /* Ignore further trailing IFS whitespace */
1410 for (; p < string + ifsp->endoff; p++) { 1410 for (; p < string + ifsp->endoff; p++) {
1411 q = p; 1411 q = p;
1412 if (*p == CTLNONL) 1412 if (*p == CTLNONL)
1413 continue; 1413 continue;
1414 if (*p == CTLESC) 1414 if (*p == CTLESC)
1415 p++; 1415 p++;
1416 if (strchr(ifs, *p) == NULL) { 1416 if (strchr(ifs, *p) == NULL) {
1417 p = q; 1417 p = q;
1418 break; 1418 break;
1419 } 1419 }
1420 if (strchr(" \t\n", *p) == NULL) { 1420 if (strchr(" \t\n", *p) == NULL) {
1421 p++; 1421 p++;
1422 break; 1422 break;
1423 } 1423 }
1424 } 1424 }
1425 } 1425 }
1426 start = p; 1426 start = p;
1427 } 1427 }
1428 } 1428 }
1429 1429
1430/* 1430/*
1431 while (*start == CTLQUOTEEND) 1431 while (*start == CTLQUOTEEND)
1432 start++; 1432 start++;
1433*/ 1433*/
1434 1434
1435 /* 1435 /*
1436 * Save anything left as an argument. 1436 * Save anything left as an argument.
1437 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as 1437 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1438 * generating 2 arguments, the second of which is empty. 1438 * generating 2 arguments, the second of which is empty.
1439 * Some recent clarification of the Posix spec say that it 1439 * Some recent clarification of the Posix spec say that it
1440 * should only generate one.... 1440 * should only generate one....
1441 */ 1441 */
1442 if (had_param_ch || *start != 0) { 1442 if (had_param_ch || *start != 0) {
1443 VTRACE(DBG_EXPAND, (" T<%s>", start)); 1443 VTRACE(DBG_EXPAND, (" T<%s>", start));
1444 sp = stalloc(sizeof(*sp)); 1444 sp = stalloc(sizeof(*sp));
1445 sp->text = start; 1445 sp->text = start;
1446 *arglist->lastp = sp; 1446 *arglist->lastp = sp;
1447 arglist->lastp = &sp->next; 1447 arglist->lastp = &sp->next;
1448 } 1448 }
1449 VTRACE(DBG_EXPAND, ("\n")); 1449 VTRACE(DBG_EXPAND, ("\n"));
1450} 1450}
1451 1451
1452STATIC void 1452STATIC void
1453ifsfree(void) 1453ifsfree(void)
1454{ 1454{
1455 while (ifsfirst.next != NULL) { 1455 while (ifsfirst.next != NULL) {
1456 struct ifsregion *ifsp; 1456 struct ifsregion *ifsp;
1457 INTOFF; 1457 INTOFF;
1458 ifsp = ifsfirst.next->next; 1458 ifsp = ifsfirst.next->next;
1459 ckfree(ifsfirst.next); 1459 ckfree(ifsfirst.next);
1460 ifsfirst.next = ifsp; 1460 ifsfirst.next = ifsp;
1461 INTON; 1461 INTON;
1462 } 1462 }
1463 ifslastp = NULL; 1463 ifslastp = NULL;
1464 ifsfirst.next = NULL; 1464 ifsfirst.next = NULL;
1465} 1465}
1466 1466
1467 1467
1468 1468
1469/* 1469/*
1470 * Expand shell metacharacters. At this point, the only control characters 1470 * Expand shell metacharacters. At this point, the only control characters
1471 * should be escapes. The results are stored in the list exparg. 1471 * should be escapes. The results are stored in the list exparg.
1472 */ 1472 */
1473 1473
1474char *expdir; 1474char *expdir;
1475 1475
1476 1476
1477STATIC void 1477STATIC void
1478expandmeta(struct strlist *str, int flag) 1478expandmeta(struct strlist *str, int flag)
1479{ 1479{
1480 char *p; 1480 char *p;
1481 struct strlist **savelastp; 1481 struct strlist **savelastp;
1482 struct strlist *sp; 1482 struct strlist *sp;
1483 char c; 1483 char c;
1484 /* TODO - EXP_REDIR */ 1484 /* TODO - EXP_REDIR */
1485 1485
1486 while (str) { 1486 while (str) {
1487 p = str->text; 1487 p = str->text;
1488 for (;;) { /* fast check for meta chars */ 1488 for (;;) { /* fast check for meta chars */
1489 if ((c = *p++) == '\0') 1489 if ((c = *p++) == '\0')
1490 goto nometa; 1490 goto nometa;
1491 if (c == '*' || c == '?' || c == '[' /* || c == '!' */) 1491 if (c == '*' || c == '?' || c == '[' /* || c == '!' */)
1492 break; 1492 break;
1493 } 1493 }
1494 savelastp = exparg.lastp; 1494 savelastp = exparg.lastp;
1495 INTOFF; 1495 INTOFF;
1496 if (expdir == NULL) { 1496 if (expdir == NULL) {
1497 int i = strlen(str->text); 1497 int i = strlen(str->text);
1498 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 1498 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
1499 } 1499 }
1500 1500
1501 expmeta(expdir, str->text); 1501 expmeta(expdir, str->text);
1502 ckfree(expdir); 1502 ckfree(expdir);
1503 expdir = NULL; 1503 expdir = NULL;
1504 INTON; 1504 INTON;
1505 if (exparg.lastp == savelastp) { 1505 if (exparg.lastp == savelastp) {
1506 /* 1506 /*
1507 * no matches 1507 * no matches
1508 */ 1508 */
1509 nometa: 1509 nometa:
1510 *exparg.lastp = str; 1510 *exparg.lastp = str;
1511 rmescapes(str->text); 1511 rmescapes(str->text);
1512 exparg.lastp = &str->next; 1512 exparg.lastp = &str->next;
1513 } else { 1513 } else {
1514 *exparg.lastp = NULL; 1514 *exparg.lastp = NULL;
1515 *savelastp = sp = expsort(*savelastp); 1515 *savelastp = sp = expsort(*savelastp);
1516 while (sp->next != NULL) 1516 while (sp->next != NULL)
1517 sp = sp->next; 1517 sp = sp->next;
1518 exparg.lastp = &sp->next; 1518 exparg.lastp = &sp->next;
1519 } 1519 }
1520 str = str->next; 1520 str = str->next;
1521 } 1521 }
1522} 1522}
1523 1523
1524STATIC void 1524STATIC void
1525add_args(struct strlist *str) 1525add_args(struct strlist *str)
1526{ 1526{
1527 while (str) { 1527 while (str) {
1528 *exparg.lastp = str; 1528 *exparg.lastp = str;
1529 rmescapes(str->text); 1529 rmescapes(str->text);
1530 exparg.lastp = &str->next; 1530 exparg.lastp = &str->next;
1531 str = str->next; 1531 str = str->next;
1532 } 1532 }
1533} 1533}
1534 1534
1535 1535
1536/* 1536/*
1537 * Do metacharacter (i.e. *, ?, [...]) expansion. 1537 * Do metacharacter (i.e. *, ?, [...]) expansion.
1538 */ 1538 */
1539 1539
1540STATIC void 1540STATIC void
1541expmeta(char *enddir, char *name) 1541expmeta(char *enddir, char *name)
1542{ 1542{
1543 char *p; 1543 char *p;
1544 const char *cp; 1544 const char *cp;
1545 char *q; 1545 char *q;
1546 char *start; 1546 char *start;
1547 char *endname; 1547 char *endname;
1548 int metaflag; 1548 int metaflag;
1549 struct stat statb; 1549 struct stat statb;
1550 DIR *dirp; 1550 DIR *dirp;
1551 struct dirent *dp; 1551 struct dirent *dp;
1552 int atend; 1552 int atend;
1553 int matchdot; 1553 int matchdot;
1554 1554
1555 CTRACE(DBG_EXPAND|DBG_MATCH, ("expmeta(\"%s\")\n", name)); 1555 CTRACE(DBG_EXPAND|DBG_MATCH, ("expmeta(\"%s\")\n", name));
1556 metaflag = 0; 1556 metaflag = 0;
1557 start = name; 1557 start = name;
1558 for (p = name ; ; p++) { 1558 for (p = name ; ; p++) {
1559 if (*p == '*' || *p == '?') 1559 if (*p == '*' || *p == '?')
1560 metaflag = 1; 1560 metaflag = 1;
1561 else if (*p == '[') { 1561 else if (*p == '[') {
1562 q = p + 1; 1562 q = p + 1;
1563 if (*q == '!' || *q == '^') 1563 if (*q == '!' || *q == '^')
1564 q++; 1564 q++;
1565 for (;;) { 1565 for (;;) {
1566 while (IS_BORING(*q)) 1566 while (IS_BORING(*q))
1567 q++; 1567 q++;
1568 if (*q == ']') { 1568 if (*q == ']') {
1569 q++; 1569 q++;
1570 metaflag = 1; 1570 metaflag = 1;
1571 break; 1571 break;
1572 } 1572 }
1573 if (*q == '[' && q[1] == ':') { 1573 if (*q == '[' && q[1] == ':') {
1574 /* 1574 /*
1575 * character class, look for :] ending 1575 * character class, look for :] ending
1576 * also stop on ']' (end bracket expr) 1576 * also stop on ']' (end bracket expr)
1577 * or '\0' or '/' (end pattern) 1577 * or '\0' or '/' (end pattern)
1578 */ 1578 */
1579 while (*++q != '\0' && *q != ']' && 1579 while (*++q != '\0' && *q != ']' &&
1580 *q != '/') { 1580 *q != '/') {
1581 if (*q == CTLESC) { 1581 if (*q == CTLESC) {
1582 if (*++q == '\0') 1582 if (*++q == '\0')
1583 break; 1583 break;
1584 if (*q == '/') 1584 if (*q == '/')
1585 break; 1585 break;
1586 } else if (*q == ':' && 1586 } else if (*q == ':' &&
1587 q[1] == ']') 1587 q[1] == ']')
1588 break; 1588 break;
1589 } 1589 }
1590 if (*q == ':') { 1590 if (*q == ':') {
1591 /* 1591 /*
1592 * stopped at ':]' 1592 * stopped at ':]'
1593 * still in [...] 1593 * still in [...]
1594 * skip ":]" and continue; 1594 * skip ":]" and continue;
1595 */ 1595 */
1596 q += 2; 1596 q += 2;
1597 continue; 1597 continue;
1598 } 1598 }
1599 1599
1600 /* done at end of pattern, not [...] */ 1600 /* done at end of pattern, not [...] */
1601 if (*q == '\0' || *q == '/') 1601 if (*q == '\0' || *q == '/')
1602 break; 1602 break;
1603 1603
1604 /* found the ']', we have a [...] */ 1604 /* found the ']', we have a [...] */
1605 metaflag = 1; 1605 metaflag = 1;
1606 q++; /* skip ']' */ 1606 q++; /* skip ']' */
1607 break; 1607 break;
1608 } 1608 }
1609 if (*q == CTLESC) 1609 if (*q == CTLESC)
1610 q++; 1610 q++;
1611 /* end of pattern cannot be escaped */ 1611 /* end of pattern cannot be escaped */
1612 if (*q == '/' || *q == '\0') 1612 if (*q == '/' || *q == '\0')
1613 break; 1613 break;
1614 q++; 1614 q++;
1615 } 1615 }
1616 } else if (*p == '\0') 1616 } else if (*p == '\0')
1617 break; 1617 break;
1618 else if (IS_BORING(*p)) 1618 else if (IS_BORING(*p))
1619 continue; 1619 continue;
1620 else if (*p == CTLESC) 1620 else if (*p == CTLESC)
1621 p++; 1621 p++;
1622 if (*p == '/') { 1622 if (*p == '/') {
1623 if (metaflag) 1623 if (metaflag)
1624 break; 1624 break;
1625 start = p + 1; 1625 start = p + 1;
1626 } 1626 }
1627 } 1627 }
1628 if (metaflag == 0) { /* we've reached the end of the file name */ 1628 if (metaflag == 0) { /* we've reached the end of the file name */
1629 if (enddir != expdir) 1629 if (enddir != expdir)
1630 metaflag++; 1630 metaflag++;
1631 for (p = name ; ; p++) { 1631 for (p = name ; ; p++) {
1632 if (IS_BORING(*p)) 1632 if (IS_BORING(*p))
1633 continue; 1633 continue;
1634 if (*p == CTLESC) 1634 if (*p == CTLESC)
1635 p++; 1635 p++;
1636 *enddir++ = *p; 1636 *enddir++ = *p;
1637 if (*p == '\0') 1637 if (*p == '\0')
1638 break; 1638 break;
1639 } 1639 }
1640 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 1640 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1641 addfname(expdir); 1641 addfname(expdir);
1642 return; 1642 return;
1643 } 1643 }
1644 endname = p; 1644 endname = p;
1645 if (start != name) { 1645 if (start != name) {
1646 p = name; 1646 p = name;
1647 while (p < start) { 1647 while (p < start) {
1648 while (IS_BORING(*p)) 1648 while (IS_BORING(*p))
1649 p++; 1649 p++;
1650 if (*p == CTLESC) 1650 if (*p == CTLESC)
1651 p++; 1651 p++;
1652 *enddir++ = *p++; 1652 *enddir++ = *p++;
1653 } 1653 }
1654 } 1654 }
1655 if (enddir == expdir) { 1655 if (enddir == expdir) {
1656 cp = "."; 1656 cp = ".";
1657 } else if (enddir == expdir + 1 && *expdir == '/') { 1657 } else if (enddir == expdir + 1 && *expdir == '/') {
1658 cp = "/"; 1658 cp = "/";
1659 } else { 1659 } else {
1660 cp = expdir; 1660 cp = expdir;
1661 enddir[-1] = '\0'; 1661 enddir[-1] = '\0';
1662 } 1662 }
1663 if ((dirp = opendir(cp)) == NULL) 1663 if ((dirp = opendir(cp)) == NULL)
1664 return; 1664 return;
1665 if (enddir != expdir) 1665 if (enddir != expdir)
1666 enddir[-1] = '/'; 1666 enddir[-1] = '/';
1667 if (*endname == 0) { 1667 if (*endname == 0) {
1668 atend = 1; 1668 atend = 1;
1669 } else { 1669 } else {
1670 atend = 0; 1670 atend = 0;
1671 *endname++ = '\0'; 1671 *endname++ = '\0';
1672 } 1672 }
1673 matchdot = 0; 1673 matchdot = 0;
1674 p = start; 1674 p = start;
1675 while (IS_BORING(*p)) 1675 while (IS_BORING(*p))
1676 p++; 1676 p++;
1677 if (*p == CTLESC) 1677 if (*p == CTLESC)
1678 p++; 1678 p++;
1679 if (*p == '.') 1679 if (*p == '.')
1680 matchdot++; 1680 matchdot++;
1681 while (! int_pending() && (dp = readdir(dirp)) != NULL) { 1681 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1682 if (dp->d_name[0] == '.' && ! matchdot) 1682 if (dp->d_name[0] == '.' && ! matchdot)
1683 continue; 1683 continue;
1684 if (patmatch(start, dp->d_name, 0)) { 1684 if (patmatch(start, dp->d_name, 0)) {
1685 if (atend) { 1685 if (atend) {
1686 scopy(dp->d_name, enddir); 1686 scopy(dp->d_name, enddir);
1687 addfname(expdir); 1687 addfname(expdir);
1688 } else { 1688 } else {
1689 for (p = enddir, cp = dp->d_name; 1689 for (p = enddir, cp = dp->d_name;
1690 (*p++ = *cp++) != '\0';) 1690 (*p++ = *cp++) != '\0';)
1691 continue; 1691 continue;
1692 p[-1] = '/'; 1692 p[-1] = '/';
1693 expmeta(p, endname); 1693 expmeta(p, endname);
1694 } 1694 }
1695 } 1695 }
1696 } 1696 }
1697 closedir(dirp); 1697 closedir(dirp);
1698 if (! atend) 1698 if (! atend)
1699 endname[-1] = '/'; 1699 endname[-1] = '/';
1700} 1700}
1701 1701
1702 1702
1703/* 1703/*
1704 * Add a file name to the list. 1704 * Add a file name to the list.
1705 */ 1705 */
1706 1706
1707STATIC void 1707STATIC void
1708addfname(char *name) 1708addfname(char *name)
1709{ 1709{
1710 char *p; 1710 char *p;
1711 struct strlist *sp; 1711 struct strlist *sp;
1712 1712
1713 p = stalloc(strlen(name) + 1); 1713 p = stalloc(strlen(name) + 1);
1714 scopy(name, p); 1714 scopy(name, p);
1715 sp = stalloc(sizeof(*sp)); 1715 sp = stalloc(sizeof(*sp));
1716 sp->text = p; 1716 sp->text = p;
1717 *exparg.lastp = sp; 1717 *exparg.lastp = sp;
1718 exparg.lastp = &sp->next; 1718 exparg.lastp = &sp->next;
1719} 1719}
1720 1720
1721 1721
1722/* 1722/*
1723 * Sort the results of file name expansion. It calculates the number of 1723 * Sort the results of file name expansion. It calculates the number of
1724 * strings to sort and then calls msort (short for merge sort) to do the 1724 * strings to sort and then calls msort (short for merge sort) to do the
1725 * work. 1725 * work.
1726 */ 1726 */
1727 1727
1728STATIC struct strlist * 1728STATIC struct strlist *
1729expsort(struct strlist *str) 1729expsort(struct strlist *str)
1730{ 1730{
1731 int len; 1731 int len;
1732 struct strlist *sp; 1732 struct strlist *sp;
1733 1733
1734 len = 0; 1734 len = 0;
1735 for (sp = str ; sp ; sp = sp->next) 1735 for (sp = str ; sp ; sp = sp->next)
1736 len++; 1736 len++;
1737 return msort(str, len); 1737 return msort(str, len);
1738} 1738}
1739 1739
1740 1740
1741STATIC struct strlist * 1741STATIC struct strlist *
1742msort(struct strlist *list, int len) 1742msort(struct strlist *list, int len)
1743{ 1743{
1744 struct strlist *p, *q = NULL; 1744 struct strlist *p, *q = NULL;
1745 struct strlist **lpp; 1745 struct strlist **lpp;
1746 int half; 1746 int half;
1747 int n; 1747 int n;
1748 1748
1749 if (len <= 1) 1749 if (len <= 1)
1750 return list; 1750 return list;
1751 half = len >> 1; 1751 half = len >> 1;
1752 p = list; 1752 p = list;
1753 for (n = half ; --n >= 0 ; ) { 1753 for (n = half ; --n >= 0 ; ) {
1754 q = p; 1754 q = p;
1755 p = p->next; 1755 p = p->next;
1756 } 1756 }
1757 q->next = NULL; /* terminate first half of list */ 1757 q->next = NULL; /* terminate first half of list */
1758 q = msort(list, half); /* sort first half of list */ 1758 q = msort(list, half); /* sort first half of list */
1759 p = msort(p, len - half); /* sort second half */ 1759 p = msort(p, len - half); /* sort second half */
1760 lpp = &list; 1760 lpp = &list;
1761 for (;;) { 1761 for (;;) {
1762 if (strcmp(p->text, q->text) < 0) { 1762 if (strcmp(p->text, q->text) < 0) {
1763 *lpp = p; 1763 *lpp = p;
1764 lpp = &p->next; 1764 lpp = &p->next;
1765 if ((p = *lpp) == NULL) { 1765 if ((p = *lpp) == NULL) {
1766 *lpp = q; 1766 *lpp = q;
1767 break; 1767 break;
1768 } 1768 }
1769 } else { 1769 } else {
1770 *lpp = q; 1770 *lpp = q;
1771 lpp = &q->next; 1771 lpp = &q->next;
1772 if ((q = *lpp) == NULL) { 1772 if ((q = *lpp) == NULL) {
1773 *lpp = p; 1773 *lpp = p;
1774 break; 1774 break;
1775 } 1775 }
1776 } 1776 }
1777 } 1777 }
1778 return list; 1778 return list;
1779} 1779}
1780 1780
1781 1781
1782/* 1782/*
1783 * See if a character matches a character class, starting at the first colon 1783 * See if a character matches a character class, starting at the first colon
1784 * of "[:class:]". 1784 * of "[:class:]".
1785 * If a valid character class is recognized, a pointer to the next character 1785 * If a valid character class is recognized, a pointer to the next character
1786 * after the final closing bracket is stored into *end, otherwise a null 1786 * after the final closing bracket is stored into *end, otherwise a null
1787 * pointer is stored into *end. 1787 * pointer is stored into *end.
1788 */ 1788 */
1789static int 1789static int
1790match_charclass(const char *p, wchar_t chr, const char **end) 1790match_charclass(const char *p, wchar_t chr, const char **end)
1791{ 1791{
1792 char name[20]; 1792 char name[20];
1793 char *nameend; 1793 char *nameend;
1794 wctype_t cclass; 1794 wctype_t cclass;
 1795 char *q;
1795 1796
1796 *end = NULL; 1797 *end = NULL;
1797 p++; 1798 p++;
 1799 q = &name[0];
1798 nameend = strstr(p, ":]"); 1800 nameend = strstr(p, ":]");
1799 if (nameend == NULL || nameend == p) /* not a valid class */ 1801 if (nameend == NULL || nameend == p) /* not a valid class */
1800 return 0; 1802 return 0;
1801 1803
1802 if (!is_alpha(*p) || strspn(p, /* '_' is a local extension */ 1804 if (*p == CTLESC) {
1803 "0123456789" "_" 1805 if (*++p == CTLESC)
1804 "abcdefghijklmnopqrstuvwxyz" 1806 return 0;
1805 "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != (size_t)(nameend - p)) 1807 if (p == nameend)
 1808 return 0;
 1809 }
 1810 if (!is_alpha(*p))
1806 return 0; 1811 return 0;
 1812 while (p < nameend) {
 1813 if (*p == CTLESC) {
 1814 p++;
 1815 if (p == nameend)
 1816 return 0;
 1817 }
 1818 if (!is_in_name(*p)) /* '_' is a local extension */
 1819 return 0;
 1820 if (q < &name[sizeof name])
 1821 *q++ = *p++;
 1822 else
 1823 p++;
 1824 }
1807 1825
1808 *end = nameend + 2; /* committed to it being a char class */ 1826 *end = nameend + 2; /* committed to it being a char class */
1809 if ((size_t)(nameend - p) >= sizeof(name)) /* but too long */ 1827
1810 return 0; /* so no match */ 1828 if (q < &name[sizeof name]) /* a usable name found */
1811 memcpy(name, p, nameend - p); 1829 *q++ = '\0';
1812 name[nameend - p] = '\0'; 1830 else /* too long, valid, but no match */
 1831 return 0;
 1832
1813 cclass = wctype(name); 1833 cclass = wctype(name);
1814 /* An unknown class matches nothing but is valid nevertheless. */ 1834 /* An unknown class matches nothing but is valid nevertheless. */
1815 if (cclass == 0) 1835 if (cclass == 0)
1816 return 0; 1836 return 0;
1817 return iswctype(chr, cclass); 1837 return iswctype(chr, cclass);
1818} 1838}
1819 1839
1820 1840
1821/* 1841/*
1822 * Returns true if the pattern matches the string. 1842 * Returns true if the pattern matches the string.
1823 */ 1843 */
1824 1844
1825STATIC int 1845STATIC int
1826patmatch(const char *pattern, const char *string, int squoted) 1846patmatch(const char *pattern, const char *string, int squoted)
1827{ 1847{
1828 const char *p, *q, *end; 1848 const char *p, *q, *end;
1829 const char *bt_p, *bt_q; 1849 const char *bt_p, *bt_q;
1830 char c; 1850 char c;
1831 wchar_t wc, wc2; 1851 wchar_t wc, wc2;
1832 1852
1833 VTRACE(DBG_MATCH, ("patmatch(P=\"%s\", W=\"%s\"%s): ", 1853 VTRACE(DBG_MATCH, ("patmatch(P=\"%s\", W=\"%s\"%s): ",
1834 pattern, string, squoted ? ", SQ" : "")); 1854 pattern, string, squoted ? ", SQ" : ""));
1835 p = pattern; 1855 p = pattern;
1836 q = string; 1856 q = string;
1837 bt_p = NULL; 1857 bt_p = NULL;
1838 bt_q = NULL; 1858 bt_q = NULL;
1839 for (;;) { 1859 for (;;) {
1840 switch (c = *p++) { 1860 switch (c = *p++) {
1841 case '\0': 1861 case '\0':
1842 if (squoted && *q == CTLESC) { 1862 if (squoted && *q == CTLESC) {
1843 if (q[1] == '\0') 1863 if (q[1] == '\0')
1844 q++; 1864 q++;
1845 } 1865 }
1846 if (*q != '\0') 1866 if (*q != '\0')
1847 goto backtrack; 1867 goto backtrack;
1848 VTRACE(DBG_MATCH, ("match\n")); 1868 VTRACE(DBG_MATCH, ("match\n"));
1849 return 1; 1869 return 1;
1850 case CTLESC: 1870 case CTLESC:
1851 if (squoted && *q == CTLESC) 1871 if (squoted && *q == CTLESC)
1852 q++; 1872 q++;
1853 if (*p == '\0' && *q == '\0') { 1873 if (*p == '\0' && *q == '\0') {
1854 VTRACE(DBG_MATCH, ("match-\\\n")); 1874 VTRACE(DBG_MATCH, ("match-\\\n"));
1855 return 1; 1875 return 1;
1856 } 1876 }
1857 if (*q++ != *p++) 1877 if (*q++ != *p++)
1858 goto backtrack; 1878 goto backtrack;
1859 break; 1879 break;
1860 case '\\': 1880 case '\\':
1861 if (squoted && *q == CTLESC) 1881 if (squoted && *q == CTLESC)
1862 q++; 1882 q++;
1863 if (*q++ != *p++) 1883 if (*q++ != *p++)
1864 goto backtrack; 1884 goto backtrack;
1865 break; 1885 break;
1866 case CTLQUOTEMARK: 1886 case CTLQUOTEMARK:
1867 case CTLQUOTEEND: 1887 case CTLQUOTEEND:
1868 case CTLNONL: 1888 case CTLNONL:
1869 continue; 1889 continue;
1870 case '?': 1890 case '?':
1871 if (squoted && *q == CTLESC) 1891 if (squoted && *q == CTLESC)
1872 q++; 1892 q++;
1873 if (*q++ == '\0') { 1893 if (*q++ == '\0') {
1874 VTRACE(DBG_MATCH, ("?fail\n")); 1894 VTRACE(DBG_MATCH, ("?fail\n"));
1875 return 0; 1895 return 0;
1876 } 1896 }
1877 break; 1897 break;
1878 case '*': 1898 case '*':
1879 c = *p; 1899 c = *p;
1880 while (c == CTLQUOTEMARK || c == '*') 1900 while (c == CTLQUOTEMARK || c == '*')
1881 c = *++p; 1901 c = *++p;
1882 if (c != CTLESC && !IS_BORING(c) && 1902 if (c != CTLESC && !IS_BORING(c) &&
1883 c != '?' && c != '*' && c != '[') { 1903 c != '?' && c != '*' && c != '[') {
1884 while (*q != c) { 1904 while (*q != c) {
1885 if (squoted && *q == CTLESC && 1905 if (squoted && *q == CTLESC &&
1886 q[1] == c) 1906 q[1] == c)
1887 break; 1907 break;
1888 if (*q == '\0') { 1908 if (*q == '\0') {
1889 VTRACE(DBG_MATCH, ("*fail\n")); 1909 VTRACE(DBG_MATCH, ("*fail\n"));
1890 return 0; 1910 return 0;
1891 } 1911 }
1892 if (squoted && *q == CTLESC) 1912 if (squoted && *q == CTLESC)
1893 q++; 1913 q++;
1894 q++; 1914 q++;
1895 } 1915 }
1896 } 1916 }
1897 if (c == CTLESC && p[1] == '\0') { 1917 if (c == CTLESC && p[1] == '\0') {
1898 VTRACE(DBG_MATCH, ("match+\\\n")); 1918 VTRACE(DBG_MATCH, ("match+\\\n"));
1899 return 1; 1919 return 1;
1900 } 1920 }
1901 /* 1921 /*
1902 * First try the shortest match for the '*' that 1922 * First try the shortest match for the '*' that
1903 * could work. We can forget any earlier '*' since 1923 * could work. We can forget any earlier '*' since
1904 * there is no way having it match more characters 1924 * there is no way having it match more characters
1905 * can help us, given that we are already here. 1925 * can help us, given that we are already here.
1906 */ 1926 */
1907 bt_p = p; 1927 bt_p = p;
1908 bt_q = q; 1928 bt_q = q;
1909 break; 1929 break;
1910 case '[': { 1930 case '[': {
1911 const char *savep, *saveq, *endp; 1931 const char *savep, *saveq, *endp;
1912 int invert, found; 1932 int invert, found;
1913 unsigned char chr; 1933 unsigned char chr;
1914 1934
1915 /* 1935 /*
1916 * First quick check to see if there is a 1936 * First quick check to see if there is a
1917 * possible matching ']' - if not, then this 1937 * possible matching ']' - if not, then this
1918 * is not a char class, and the '[' is just 1938 * is not a char class, and the '[' is just
1919 * a literal '['. 1939 * a literal '['.
1920 * 1940 *
1921 * This check will not detect all non classes, but 1941 * This check will not detect all non classes, but
1922 * that's OK - It just means that we execute the 1942 * that's OK - It just means that we execute the
1923 * harder code sometimes when it it cannot succeed. 1943 * harder code sometimes when it it cannot succeed.
1924 */ 1944 */
1925 endp = p; 1945 endp = p;
1926 if (*endp == '!' || *endp == '^') 1946 if (*endp == '!' || *endp == '^')
1927 endp++; 1947 endp++;
1928 for (;;) { 1948 for (;;) {
1929 while (IS_BORING(*endp)) 1949 while (IS_BORING(*endp))
1930 endp++; 1950 endp++;
1931 if (*endp == '\0') 1951 if (*endp == '\0')
1932 goto dft; /* no matching ] */ 1952 goto dft; /* no matching ] */
1933 if (*endp++ == ']') 1953 if (*endp++ == ']')
1934 break; 1954 break;
1935 } 1955 }
1936 /* end shortcut */ 1956 /* end shortcut */
1937 1957
1938 invert = 0; 1958 invert = 0;
1939 savep = p, saveq = q; 1959 savep = p, saveq = q;
1940 invert = 0; 1960 invert = 0;
1941 if (*p == '!' || *p == '^') { 1961 if (*p == '!' || *p == '^') {
1942 invert++; 1962 invert++;
1943 p++; 1963 p++;
1944 } 1964 }
1945 found = 0; 1965 found = 0;
1946 if (*q == '\0') { 1966 if (*q == '\0') {
1947 VTRACE(DBG_MATCH, ("[]fail\n")); 1967 VTRACE(DBG_MATCH, ("[]fail\n"));
1948 return 0; 1968 return 0;
1949 } 1969 }
1950 if (squoted && *q == CTLESC) 1970 if (squoted && *q == CTLESC)
1951 q++; 1971 q++;
1952 chr = (unsigned char)*q++; 1972 chr = (unsigned char)*q++;
1953 c = *p++; 1973 c = *p++;
1954 do { 1974 do {
1955 if (IS_BORING(c)) 1975 if (IS_BORING(c))
1956 continue; 1976 continue;
1957 if (c == '\0') { 1977 if (c == '\0') {
1958 p = savep, q = saveq; 1978 p = savep, q = saveq;
1959 c = '['; 1979 c = '[';
1960 goto dft; 1980 goto dft;
1961 } 1981 }
1962 if (c == '[' && *p == ':') { 1982 if (c == '[' && *p == ':') {
1963 found |= match_charclass(p, chr, &end); 1983 found |= match_charclass(p, chr, &end);
1964 if (end != NULL) { 1984 if (end != NULL) {
1965 p = end; 1985 p = end;
1966 continue; 1986 continue;
1967 } 1987 }
1968 } 1988 }
1969 if (c == CTLESC || c == '\\') 1989 if (c == CTLESC || c == '\\')
1970 c = *p++; 1990 c = *p++;
1971 wc = (unsigned char)c; 1991 wc = (unsigned char)c;
1972 if (*p == '-' && p[1] != ']') { 1992 if (*p == '-' && p[1] != ']') {
1973 p++; 1993 p++;
1974 if (*p == CTLESC || *p == '\\') 1994 if (*p == CTLESC || *p == '\\')
1975 p++; 1995 p++;
1976 wc2 = (unsigned char)*p++; 1996 wc2 = (unsigned char)*p++;
1977 if ( collate_range_cmp(chr, wc) >= 0 1997 if ( collate_range_cmp(chr, wc) >= 0
1978 && collate_range_cmp(chr, wc2) <= 0 1998 && collate_range_cmp(chr, wc2) <= 0
1979 ) 1999 )
1980 found = 1; 2000 found = 1;
1981 } else { 2001 } else {
1982 if (chr == wc) 2002 if (chr == wc)
1983 found = 1; 2003 found = 1;
1984 } 2004 }
1985 } while ((c = *p++) != ']'); 2005 } while ((c = *p++) != ']');
1986 if (found == invert) 2006 if (found == invert)
1987 goto backtrack; 2007 goto backtrack;
1988 break; 2008 break;
1989 } 2009 }
1990 dft: default: 2010 dft: default:
1991 if (squoted && *q == CTLESC) 2011 if (squoted && *q == CTLESC)
1992 q++; 2012 q++;
1993 if (*q++ == c) 2013 if (*q++ == c)
1994 break; 2014 break;
1995 backtrack: 2015 backtrack:
1996 /* 2016 /*
1997 * If we have a mismatch (other than hitting the end 2017 * If we have a mismatch (other than hitting the end
1998 * of the string), go back to the last '*' seen and 2018 * of the string), go back to the last '*' seen and
1999 * have it match one additional character. 2019 * have it match one additional character.
2000 */ 2020 */
2001 if (bt_p == NULL) { 2021 if (bt_p == NULL) {
2002 VTRACE(DBG_MATCH, ("BTP fail\n")); 2022 VTRACE(DBG_MATCH, ("BTP fail\n"));
2003 return 0; 2023 return 0;
2004 } 2024 }
2005 if (*bt_q == '\0') { 2025 if (*bt_q == '\0') {
2006 VTRACE(DBG_MATCH, ("BTQ fail\n")); 2026 VTRACE(DBG_MATCH, ("BTQ fail\n"));
2007 return 0; 2027 return 0;
2008 } 2028 }
2009 bt_q++; 2029 bt_q++;
2010 p = bt_p; 2030 p = bt_p;
2011 q = bt_q; 2031 q = bt_q;
2012 break; 2032 break;
2013 } 2033 }
2014 } 2034 }
2015} 2035}
2016 2036
2017 2037
2018 2038
2019/* 2039/*
2020 * Remove any CTLESC or CTLNONL characters from a string. 2040 * Remove any CTLESC or CTLNONL characters from a string.
2021 */ 2041 */
2022 2042
2023void 2043void
2024rmescapes(char *str) 2044rmescapes(char *str)
2025{ 2045{
2026 char *p, *q; 2046 char *p, *q;
2027 2047
2028 p = str; 2048 p = str;
2029 while (!ISCTL(*p)) { 2049 while (!ISCTL(*p)) {
2030 if (*p++ == '\0') 2050 if (*p++ == '\0')
2031 return; 2051 return;
2032 } 2052 }
2033 q = p; 2053 q = p;
2034 while (*p) { 2054 while (*p) {
2035 if (IS_BORING(*p)) { 2055 if (IS_BORING(*p)) {
2036 p++; 2056 p++;
2037 continue; 2057 continue;
2038 } 2058 }
2039 if (*p == CTLCNL) { 2059 if (*p == CTLCNL) {
2040 p++; 2060 p++;
2041 *q++ = '\n'; 2061 *q++ = '\n';
2042 continue; 2062 continue;
2043 } 2063 }
2044 if (*p == CTLESC) 2064 if (*p == CTLESC)
2045 p++; 2065 p++;
2046#ifdef DEBUG 2066#ifdef DEBUG
2047 else if (ISCTL(*p)) 2067 else if (ISCTL(*p))
2048 abort(); 2068 abort();
2049#endif 2069#endif
2050 *q++ = *p++; 2070 *q++ = *p++;
2051 } 2071 }
2052 *q = '\0'; 2072 *q = '\0';
2053} 2073}
2054 2074
2055/* 2075/*
2056 * and a special version for dealing with expressions to be parsed 2076 * and a special version for dealing with expressions to be parsed
2057 * by the arithmetic evaluator. That needs to be able to count \n's 2077 * by the arithmetic evaluator. That needs to be able to count \n's
2058 * even ones that were \newline elided \n's, so we have to put the 2078 * even ones that were \newline elided \n's, so we have to put the
2059 * latter back into the string - just being careful to put them only 2079 * latter back into the string - just being careful to put them only
2060 * at a place where white space can reasonably occur in the string 2080 * at a place where white space can reasonably occur in the string
2061 * -- then the \n we insert will just be white space, and ignored 2081 * -- then the \n we insert will just be white space, and ignored
2062 * for all purposes except line counting. 2082 * for all purposes except line counting.
2063 */ 2083 */
2064 2084
2065void 2085void
2066rmescapes_nl(char *str) 2086rmescapes_nl(char *str)
2067{ 2087{
2068 char *p, *q; 2088 char *p, *q;
2069 int nls = 0, holdnl = 0, holdlast; 2089 int nls = 0, holdnl = 0, holdlast;
2070 2090
2071 p = str; 2091 p = str;
2072 while (!ISCTL(*p)) { 2092 while (!ISCTL(*p)) {
2073 if (*p++ == '\0') 2093 if (*p++ == '\0')
2074 return; 2094 return;
2075 } 2095 }
2076 if (p > str) /* must reprocess char before stopper (if any) */ 2096 if (p > str) /* must reprocess char before stopper (if any) */
2077 --p; /* so we do not place a \n badly */ 2097 --p; /* so we do not place a \n badly */
2078 q = p; 2098 q = p;
2079 while (*p) { 2099 while (*p) {
2080 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) { 2100 if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
2081 p++; 2101 p++;
2082 continue; 2102 continue;
2083 } 2103 }
2084 if (*p == CTLNONL) { 2104 if (*p == CTLNONL) {
2085 p++; 2105 p++;
2086 nls++; 2106 nls++;
2087 continue; 2107 continue;
2088 } 2108 }
2089 if (*p == CTLCNL) { 2109 if (*p == CTLCNL) {
2090 p++; 2110 p++;
2091 *q++ = '\n'; 2111 *q++ = '\n';
2092 continue; 2112 continue;
2093 } 2113 }
2094 if (*p == CTLESC) 2114 if (*p == CTLESC)
2095 p++; 2115 p++;
2096#ifdef DEBUG 2116#ifdef DEBUG
2097 else if (ISCTL(*p)) 2117 else if (ISCTL(*p))
2098 abort(); 2118 abort();
2099#endif 2119#endif
2100 2120
2101 holdlast = holdnl; 2121 holdlast = holdnl;
2102 holdnl = is_in_name(*p); /* letters, digits, _ */ 2122 holdnl = is_in_name(*p); /* letters, digits, _ */
2103 if (q == str || is_space(q[-1]) || (*p != '=' && q[-1] != *p)) { 2123 if (q == str || is_space(q[-1]) || (*p != '=' && q[-1] != *p)) {
2104 if (nls > 0 && holdnl != holdlast) { 2124 if (nls > 0 && holdnl != holdlast) {
2105 while (nls > 0) 2125 while (nls > 0)
2106 *q++ = '\n', nls--; 2126 *q++ = '\n', nls--;
2107 } 2127 }
2108 } 2128 }
2109 *q++ = *p++; 2129 *q++ = *p++;
2110 } 2130 }
2111 while (--nls >= 0) 2131 while (--nls >= 0)
2112 *q++ = '\n'; 2132 *q++ = '\n';
2113 *q = '\0'; 2133 *q = '\0';
2114} 2134}
2115 2135
2116 2136
2117 2137
2118/* 2138/*
2119 * See if a pattern matches in a case statement. 2139 * See if a pattern matches in a case statement.
2120 */ 2140 */
2121 2141
2122int 2142int
2123casematch(union node *pattern, char *val) 2143casematch(union node *pattern, char *val)
2124{ 2144{
2125 struct stackmark smark; 2145 struct stackmark smark;
2126 int result; 2146 int result;
2127 char *p; 2147 char *p;
2128 2148
2129 CTRACE(DBG_MATCH, ("casematch(P=\"%s\", W=\"%s\")\n", 2149 CTRACE(DBG_MATCH, ("casematch(P=\"%s\", W=\"%s\")\n",
2130 pattern->narg.text, val)); 2150 pattern->narg.text, val));
2131 setstackmark(&smark); 2151 setstackmark(&smark);
2132 argbackq = pattern->narg.backquote; 2152 argbackq = pattern->narg.backquote;
2133 STARTSTACKSTR(expdest); 2153 STARTSTACKSTR(expdest);
2134 ifslastp = NULL; 2154 ifslastp = NULL;
2135 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 2155 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
2136 STPUTC('\0', expdest); 2156 STPUTC('\0', expdest);
2137 p = grabstackstr(expdest); 2157 p = grabstackstr(expdest);
2138 result = patmatch(p, val, 0); 2158 result = patmatch(p, val, 0);
2139 popstackmark(&smark); 2159 popstackmark(&smark);
2140 return result; 2160 return result;
2141} 2161}
2142 2162
2143/* 2163/*
2144 * Our own itoa(). Assumes result buffer is on the stack 2164 * Our own itoa(). Assumes result buffer is on the stack
2145 */ 2165 */
2146 2166
2147STATIC char * 2167STATIC char *
2148cvtnum(int num, char *buf) 2168cvtnum(int num, char *buf)
2149{ 2169{
2150 char temp[32]; 2170 char temp[32];
2151 int neg = num < 0; 2171 int neg = num < 0;
2152 char *p = temp + sizeof temp - 1; 2172 char *p = temp + sizeof temp - 1;
2153 2173
2154 if (neg) 2174 if (neg)
2155 num = -num; 2175 num = -num;
2156 2176
2157 *p = '\0'; 2177 *p = '\0';
2158 do { 2178 do {
2159 *--p = num % 10 + '0'; 2179 *--p = num % 10 + '0';
2160 } while ((num /= 10) != 0 && p > temp + 1); 2180 } while ((num /= 10) != 0 && p > temp + 1);
2161 2181
2162 if (neg) 2182 if (neg)
2163 *--p = '-'; 2183 *--p = '-';
2164 2184
2165 while (*p) 2185 while (*p)
2166 STPUTC(*p++, buf); 2186 STPUTC(*p++, buf);
2167 return buf; 2187 return buf;
2168} 2188}
2169 2189
2170/* 2190/*
2171 * Do most of the work for wordexp(3). 2191 * Do most of the work for wordexp(3).
2172 */ 2192 */
2173 2193
2174int 2194int
2175wordexpcmd(int argc, char **argv) 2195wordexpcmd(int argc, char **argv)
2176{ 2196{
2177 size_t len; 2197 size_t len;
2178 int i; 2198 int i;
2179 2199
2180 out1fmt("%d", argc - 1); 2200 out1fmt("%d", argc - 1);
2181 out1c('\0'); 2201 out1c('\0');
2182 for (i = 1, len = 0; i < argc; i++) 2202 for (i = 1, len = 0; i < argc; i++)
2183 len += strlen(argv[i]); 2203 len += strlen(argv[i]);
2184 out1fmt("%zu", len); 2204 out1fmt("%zu", len);
2185 out1c('\0'); 2205 out1c('\0');
2186 for (i = 1; i < argc; i++) { 2206 for (i = 1; i < argc; i++) {
2187 out1str(argv[i]); 2207 out1str(argv[i]);
2188 out1c('\0'); 2208 out1c('\0');
2189 } 2209 }
2190 return (0); 2210 return (0);
2191} 2211}