Lines 54-59
Link Here
|
54 |
#include <pwd.h> |
54 |
#include <pwd.h> |
55 |
#include <stdlib.h> |
55 |
#include <stdlib.h> |
56 |
#include <stdio.h> |
56 |
#include <stdio.h> |
|
|
57 |
#include <limits.h> |
58 |
#if defined(__GLIBC__) |
59 |
#if !defined(FNMATCH_BROKEN) |
60 |
#include <fnmatch.h> |
61 |
#if !defined(GLOB_BROKEN) |
62 |
#include <glob.h> |
63 |
#endif |
64 |
#endif |
65 |
#endif |
57 |
|
66 |
|
58 |
/* |
67 |
/* |
59 |
* Routines to expand arguments to commands. We have to deal with |
68 |
* Routines to expand arguments to commands. We have to deal with |
Lines 78-83
Link Here
|
78 |
#include "show.h" |
87 |
#include "show.h" |
79 |
|
88 |
|
80 |
/* |
89 |
/* |
|
|
90 |
* _rmescape() flags |
91 |
*/ |
92 |
#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ |
93 |
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
94 |
#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ |
95 |
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ |
96 |
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ |
97 |
|
98 |
/* |
81 |
* Structure specifying which parts of the string should be searched |
99 |
* Structure specifying which parts of the string should be searched |
82 |
* for IFS characters. |
100 |
* for IFS characters. |
83 |
*/ |
101 |
*/ |
Lines 89-122
Link Here
|
89 |
int nulonly; /* search for nul bytes only */ |
107 |
int nulonly; /* search for nul bytes only */ |
90 |
}; |
108 |
}; |
91 |
|
109 |
|
92 |
|
110 |
/* output of current string */ |
93 |
char *expdest; /* output of current string */ |
111 |
static char *expdest; |
94 |
struct nodelist *argbackq; /* list of back quote expressions */ |
112 |
/* list of back quote expressions */ |
95 |
struct ifsregion ifsfirst; /* first struct in list of ifs regions */ |
113 |
static struct nodelist *argbackq; |
96 |
struct ifsregion *ifslastp; /* last struct in list */ |
114 |
/* first struct in list of ifs regions */ |
97 |
struct arglist exparg; /* holds expanded arg list */ |
115 |
static struct ifsregion ifsfirst; |
|
|
116 |
/* last struct in list */ |
117 |
static struct ifsregion *ifslastp; |
118 |
/* holds expanded arg list */ |
119 |
static struct arglist exparg; |
98 |
|
120 |
|
99 |
STATIC void argstr __P((char *, int)); |
121 |
STATIC void argstr __P((char *, int)); |
100 |
STATIC char *exptilde __P((char *, int)); |
122 |
STATIC char *exptilde __P((char *, int)); |
101 |
STATIC void expbackq __P((union node *, int, int)); |
123 |
STATIC void expbackq __P((union node *, int, int)); |
102 |
STATIC int subevalvar __P((char *, char *, int, int, int, int)); |
124 |
STATIC const char *subevalvar __P((char *, char *, int, int, int, int, int)); |
103 |
STATIC char *evalvar __P((char *, int)); |
125 |
STATIC char *evalvar __P((char *, int)); |
104 |
STATIC int varisset __P((char *, int)); |
126 |
STATIC int varisset __P((char *, int)); |
|
|
127 |
STATIC void strtodest __P((const char *, const char *, int)); |
128 |
STATIC void memtodest __P((const char *, size_t, const char *, int)); |
105 |
STATIC void varvalue __P((char *, int, int)); |
129 |
STATIC void varvalue __P((char *, int, int)); |
106 |
STATIC void recordregion __P((int, int, int)); |
130 |
STATIC void recordregion __P((int, int, int)); |
107 |
STATIC void removerecordregions __P((int)); |
131 |
STATIC void removerecordregions __P((int)); |
108 |
STATIC void ifsbreakup __P((char *, struct arglist *)); |
132 |
STATIC void ifsbreakup __P((char *, struct arglist *)); |
109 |
STATIC void ifsfree __P((void)); |
133 |
STATIC void ifsfree __P((void)); |
110 |
STATIC void expandmeta __P((struct strlist *, int)); |
134 |
STATIC void expandmeta __P((struct strlist *, int)); |
|
|
135 |
#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) |
136 |
STATIC void addglob __P((const glob_t *)); |
137 |
#else |
111 |
STATIC void expmeta __P((char *, char *)); |
138 |
STATIC void expmeta __P((char *, char *)); |
|
|
139 |
#endif |
112 |
STATIC void addfname __P((char *)); |
140 |
STATIC void addfname __P((char *)); |
|
|
141 |
#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) |
113 |
STATIC struct strlist *expsort __P((struct strlist *)); |
142 |
STATIC struct strlist *expsort __P((struct strlist *)); |
114 |
STATIC struct strlist *msort __P((struct strlist *, int)); |
143 |
STATIC struct strlist *msort __P((struct strlist *, int)); |
115 |
STATIC int pmatch __P((char *, char *, int)); |
144 |
#endif |
116 |
STATIC char *cvtnum __P((int, char *)); |
145 |
STATIC int patmatch __P((char *, const char *)); |
|
|
146 |
#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) |
147 |
STATIC int pmatch __P((const char *, const char *)); |
148 |
#else |
149 |
#define pmatch(a, b) !fnmatch((a), (b), 0) |
150 |
#endif |
151 |
STATIC int cvtnum __P((long)); |
152 |
STATIC size_t esclen __P((const char *, const char *)); |
153 |
STATIC char *scanleft __P((char *, char *, char *, char *, int, int)); |
154 |
STATIC char *scanright __P((char *, char *, char *, char *, int, int)); |
155 |
static void varunset(const char *, const char *, const char *, int) |
156 |
__attribute__((__noreturn__)); |
117 |
|
157 |
|
118 |
extern int oexitstatus; |
158 |
extern int oexitstatus; |
119 |
|
159 |
|
|
|
160 |
|
161 |
/* |
162 |
* Prepare a pattern for a glob(3) call. |
163 |
* |
164 |
* Returns an stalloced string. |
165 |
*/ |
166 |
|
167 |
STATIC inline char * |
168 |
preglob(const char *pattern, int quoted, int flag) { |
169 |
flag |= RMESCAPE_GLOB; |
170 |
if (quoted) { |
171 |
flag |= RMESCAPE_QUOTED; |
172 |
} |
173 |
return _rmescapes((char *)pattern, flag); |
174 |
} |
175 |
|
176 |
|
177 |
STATIC size_t |
178 |
esclen(const char *start, const char *p) { |
179 |
size_t esc = 0; |
180 |
|
181 |
while (p > start && *--p == CTLESC) { |
182 |
esc++; |
183 |
} |
184 |
return esc; |
185 |
} |
186 |
|
187 |
|
120 |
/* |
188 |
/* |
121 |
* Expand shell variables and backquotes inside a here document. |
189 |
* Expand shell variables and backquotes inside a here document. |
122 |
*/ |
190 |
*/ |
Lines 196-259
Link Here
|
196 |
char *p; |
264 |
char *p; |
197 |
int flag; |
265 |
int flag; |
198 |
{ |
266 |
{ |
199 |
char c; |
267 |
static const char spclchars[] = { |
|
|
268 |
'=', |
269 |
':', |
270 |
CTLQUOTEMARK, |
271 |
CTLENDVAR, |
272 |
CTLESC, |
273 |
CTLVAR, |
274 |
CTLBACKQ, |
275 |
CTLBACKQ | CTLQUOTE, |
276 |
CTLENDARI, |
277 |
0 |
278 |
}; |
279 |
const char *reject = spclchars; |
280 |
int c; |
200 |
int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ |
281 |
int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ |
201 |
int firsteq = 1; |
282 |
int breakall = flag & EXP_WORD; |
|
|
283 |
int inquotes; |
284 |
size_t length; |
285 |
int startloc; |
202 |
|
286 |
|
203 |
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) |
287 |
if (!(flag & EXP_VARTILDE)) { |
|
|
288 |
reject += 2; |
289 |
} else if (flag & EXP_VARTILDE2) { |
290 |
reject++; |
291 |
} |
292 |
inquotes = 0; |
293 |
length = 0; |
294 |
if (flag & EXP_TILDE) { |
295 |
flag &= ~EXP_TILDE; |
296 |
tilde: |
204 |
p = exptilde(p, flag); |
297 |
p = exptilde(p, flag); |
|
|
298 |
} |
299 |
start: |
300 |
startloc = expdest - stackblock(); |
205 |
for (;;) { |
301 |
for (;;) { |
206 |
switch (c = *p++) { |
302 |
length += strcspn(p + length, reject); |
|
|
303 |
c = p[length]; |
304 |
if ((c && !(c & 0x80)) || c == CTLENDARI) { |
305 |
/* c == '=' || c == ':' || c == CTLENDARI */ |
306 |
length++; |
307 |
} |
308 |
if (length > 0) { |
309 |
int newloc; |
310 |
expdest = stnputs(p, length, expdest); |
311 |
newloc = expdest - stackblock(); |
312 |
if (breakall && !inquotes && newloc > startloc) { |
313 |
recordregion(startloc, newloc, 0); |
314 |
} |
315 |
startloc = newloc; |
316 |
} |
317 |
p += length + 1; |
318 |
length = 0; |
319 |
|
320 |
switch (c) { |
207 |
case '\0': |
321 |
case '\0': |
|
|
322 |
goto breakloop; |
323 |
case '=': |
324 |
if (flag & EXP_VARTILDE2) { |
325 |
p--; |
326 |
continue; |
327 |
} |
328 |
flag |= EXP_VARTILDE2; |
329 |
reject++; |
330 |
/* fall through */ |
331 |
case ':': |
332 |
/* |
333 |
* sort of a hack - expand tildes in variable |
334 |
* assignments (after the first '=' and after ':'s). |
335 |
*/ |
336 |
if (*--p == '~') { |
337 |
goto tilde; |
338 |
} |
339 |
continue; |
340 |
} |
341 |
|
342 |
switch (c) { |
208 |
case CTLENDVAR: /* ??? */ |
343 |
case CTLENDVAR: /* ??? */ |
209 |
goto breakloop; |
344 |
goto breakloop; |
210 |
case CTLQUOTEMARK: |
345 |
case CTLQUOTEMARK: |
211 |
/* "$@" syntax adherence hack */ |
346 |
/* "$@" syntax adherence hack */ |
212 |
if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') |
347 |
if ( |
213 |
break; |
348 |
!inquotes && |
214 |
if ((flag & EXP_FULL) != 0) |
349 |
!memcmp(p, dolatstr, DOLATSTRLEN) && |
215 |
STPUTC(c, expdest); |
350 |
(p[4] == CTLQUOTEMARK || ( |
|
|
351 |
p[4] == CTLENDVAR && |
352 |
p[5] == CTLQUOTEMARK |
353 |
)) |
354 |
) { |
355 |
p = evalvar(p + 1, flag) + 1; |
356 |
goto start; |
357 |
} |
358 |
inquotes = !inquotes; |
359 |
addquote: |
360 |
if (quotes) { |
361 |
p--; |
362 |
length++; |
363 |
startloc++; |
364 |
} |
216 |
break; |
365 |
break; |
217 |
case CTLESC: |
366 |
case CTLESC: |
218 |
if (quotes) |
367 |
startloc++; |
219 |
STPUTC(c, expdest); |
368 |
length++; |
220 |
c = *p++; |
369 |
goto addquote; |
221 |
STPUTC(c, expdest); |
|
|
222 |
break; |
223 |
case CTLVAR: |
370 |
case CTLVAR: |
224 |
p = evalvar(p, flag); |
371 |
p = evalvar(p, flag); |
225 |
break; |
372 |
goto start; |
226 |
case CTLBACKQ: |
373 |
case CTLBACKQ: |
|
|
374 |
c = 0; |
227 |
case CTLBACKQ|CTLQUOTE: |
375 |
case CTLBACKQ|CTLQUOTE: |
228 |
expbackq(argbackq->n, c & CTLQUOTE, flag); |
376 |
expbackq(argbackq->n, c, quotes); |
229 |
argbackq = argbackq->next; |
377 |
argbackq = argbackq->next; |
230 |
break; |
378 |
goto start; |
231 |
case CTLENDARI: |
379 |
case CTLENDARI: |
232 |
expari(flag); |
380 |
p--; |
233 |
break; |
381 |
expari(quotes); |
234 |
case ':': |
382 |
goto start; |
235 |
case '=': |
|
|
236 |
/* |
237 |
* sort of a hack - expand tildes in variable |
238 |
* assignments (after the first '=' and after ':'s). |
239 |
*/ |
240 |
STPUTC(c, expdest); |
241 |
if (flag & EXP_VARTILDE && *p == '~') { |
242 |
if (c == '=') { |
243 |
if (firsteq) |
244 |
firsteq = 0; |
245 |
else |
246 |
break; |
247 |
} |
248 |
p = exptilde(p, flag); |
249 |
} |
250 |
break; |
251 |
default: |
252 |
STPUTC(c, expdest); |
253 |
} |
383 |
} |
254 |
} |
384 |
} |
255 |
breakloop:; |
385 |
breakloop: |
256 |
return; |
386 |
; |
257 |
} |
387 |
} |
258 |
|
388 |
|
259 |
STATIC char * |
389 |
STATIC char * |
Lines 262-272
Link Here
|
262 |
int flag; |
392 |
int flag; |
263 |
{ |
393 |
{ |
264 |
char c, *startp = p; |
394 |
char c, *startp = p; |
|
|
395 |
char *name; |
265 |
struct passwd *pw; |
396 |
struct passwd *pw; |
266 |
const char *home; |
397 |
const char *home; |
267 |
int quotes = flag & (EXP_FULL | EXP_CASE); |
398 |
int quotes = flag & (EXP_FULL | EXP_CASE); |
|
|
399 |
int startloc; |
268 |
|
400 |
|
269 |
while ((c = *p) != '\0') { |
401 |
if (*p == CTLESC && (flag & EXP_QWORD)) { |
|
|
402 |
p++; |
403 |
} |
404 |
if (*p != '~') { |
405 |
return startp; |
406 |
} |
407 |
name = p + 1; |
408 |
|
409 |
while ((c = *++p) != '\0') { |
270 |
switch(c) { |
410 |
switch(c) { |
271 |
case CTLESC: |
411 |
case CTLESC: |
272 |
return (startp); |
412 |
return (startp); |
Lines 277-304
Link Here
|
277 |
goto done; |
417 |
goto done; |
278 |
break; |
418 |
break; |
279 |
case '/': |
419 |
case '/': |
|
|
420 |
case CTLENDVAR: |
280 |
goto done; |
421 |
goto done; |
281 |
} |
422 |
} |
282 |
p++; |
|
|
283 |
} |
423 |
} |
284 |
done: |
424 |
done: |
285 |
*p = '\0'; |
425 |
*p = '\0'; |
286 |
if (*(startp+1) == '\0') { |
426 |
if (*name == '\0') { |
287 |
if ((home = lookupvar("HOME")) == NULL) |
427 |
if ((home = lookupvar(homestr)) == NULL) |
288 |
goto lose; |
428 |
goto lose; |
289 |
} else { |
429 |
} else { |
290 |
if ((pw = getpwnam(startp+1)) == NULL) |
430 |
if ((pw = getpwnam(name)) == NULL) |
291 |
goto lose; |
431 |
goto lose; |
292 |
home = pw->pw_dir; |
432 |
home = pw->pw_dir; |
293 |
} |
433 |
} |
294 |
if (*home == '\0') |
434 |
if (*home == '\0') |
295 |
goto lose; |
435 |
goto lose; |
296 |
*p = c; |
436 |
*p = c; |
297 |
while ((c = *home++) != '\0') { |
437 |
startloc = expdest - stackblock(); |
298 |
if (quotes && SQSYNTAX[(int)c] == CCTL) |
438 |
strtodest(home, SQSYNTAX, quotes); |
299 |
STPUTC(CTLESC, expdest); |
439 |
recordregion(startloc, expdest - stackblock(), 0); |
300 |
STPUTC(c, expdest); |
|
|
301 |
} |
302 |
return (p); |
440 |
return (p); |
303 |
lose: |
441 |
lose: |
304 |
*p = c; |
442 |
*p = c; |
Lines 352-412
Link Here
|
352 |
* evaluate, place result in (backed up) result, adjust string position. |
490 |
* evaluate, place result in (backed up) result, adjust string position. |
353 |
*/ |
491 |
*/ |
354 |
void |
492 |
void |
355 |
expari(flag) |
493 |
expari(quotes) |
356 |
int flag; |
494 |
int quotes; |
357 |
{ |
495 |
{ |
358 |
char *p, *start; |
496 |
char *p, *start; |
359 |
int result; |
|
|
360 |
int begoff; |
497 |
int begoff; |
361 |
int quotes = flag & (EXP_FULL | EXP_CASE); |
498 |
int flag; |
362 |
int quoted; |
499 |
int len; |
363 |
|
500 |
|
364 |
/* ifsfree(); */ |
501 |
/* ifsfree(); */ |
365 |
|
502 |
|
366 |
/* |
503 |
/* |
367 |
* This routine is slightly over-complicated for |
504 |
* This routine is slightly over-complicated for |
368 |
* efficiency. First we make sure there is |
505 |
* efficiency. Next we scan backwards looking for the |
369 |
* enough space for the result, which may be bigger |
506 |
* start of arithmetic. |
370 |
* than the expression if we add exponentation. Next we |
|
|
371 |
* scan backwards looking for the start of arithmetic. If the |
372 |
* next previous character is a CTLESC character, then we |
373 |
* have to rescan starting from the beginning since CTLESC |
374 |
* characters have to be processed left to right. |
375 |
*/ |
507 |
*/ |
376 |
#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 |
|
|
377 |
#error "integers with more than 10 digits are not supported" |
378 |
#endif |
379 |
CHECKSTRSPACE(12 - 2, expdest); |
380 |
USTPUTC('\0', expdest); |
381 |
start = stackblock(); |
508 |
start = stackblock(); |
382 |
p = expdest - 1; |
509 |
p = expdest - 1; |
383 |
while (*p != CTLARI && p >= start) |
510 |
*p = '\0'; |
384 |
--p; |
511 |
p--; |
385 |
if (*p != CTLARI) |
512 |
do { |
|
|
513 |
int esc; |
514 |
|
515 |
while (*p != CTLARI) { |
516 |
p--; |
517 |
#ifdef DEBUG |
518 |
if (p < start) { |
386 |
error("missing CTLARI (shouldn't happen)"); |
519 |
error("missing CTLARI (shouldn't happen)"); |
387 |
if (p > start && *(p-1) == CTLESC) |
520 |
} |
388 |
for (p = start; *p != CTLARI; p++) |
521 |
#endif |
389 |
if (*p == CTLESC) |
522 |
} |
390 |
p++; |
523 |
|
|
|
524 |
esc = esclen(start, p); |
525 |
if (!(esc % 2)) { |
526 |
break; |
527 |
} |
528 |
|
529 |
p -= esc + 1; |
530 |
} while (1); |
391 |
|
531 |
|
392 |
if (p[1] == '"') |
|
|
393 |
quoted=1; |
394 |
else |
395 |
quoted=0; |
396 |
begoff = p - start; |
532 |
begoff = p - start; |
|
|
533 |
|
397 |
removerecordregions(begoff); |
534 |
removerecordregions(begoff); |
|
|
535 |
|
536 |
flag = p[1]; |
537 |
|
538 |
expdest = p; |
539 |
|
398 |
if (quotes) |
540 |
if (quotes) |
399 |
rmescapes(p+2); |
541 |
rmescapes(p + 2); |
400 |
result = arith(p+2); |
|
|
401 |
fmtstr(p, 12, "%d", result); |
402 |
|
542 |
|
403 |
while (*p++) |
543 |
len = cvtnum(arith(p + 2)); |
404 |
; |
|
|
405 |
|
544 |
|
406 |
if (quoted == 0) |
545 |
if (flag != '"') |
407 |
recordregion(begoff, p - 1 - start, 0); |
546 |
recordregion(begoff, begoff + len, 0); |
408 |
result = expdest - p + 1; |
|
|
409 |
STADJUST(-result, expdest); |
410 |
} |
547 |
} |
411 |
|
548 |
|
412 |
|
549 |
|
Lines 415-456
Link Here
|
415 |
*/ |
552 |
*/ |
416 |
|
553 |
|
417 |
STATIC void |
554 |
STATIC void |
418 |
expbackq(cmd, quoted, flag) |
555 |
expbackq(cmd, quoted, quotes) |
419 |
union node *cmd; |
556 |
union node *cmd; |
420 |
int quoted; |
557 |
int quoted; |
421 |
int flag; |
558 |
int quotes; |
422 |
{ |
559 |
{ |
423 |
struct backcmd in; |
560 |
struct backcmd in; |
424 |
int i; |
561 |
int i; |
425 |
char buf[128]; |
562 |
char buf[128]; |
426 |
char *p; |
563 |
char *p; |
427 |
char *dest = expdest; |
564 |
char *dest = expdest; |
428 |
struct ifsregion saveifs, *savelastp; |
565 |
struct ifsregion saveifs; |
|
|
566 |
struct ifsregion *savelastp; |
429 |
struct nodelist *saveargbackq; |
567 |
struct nodelist *saveargbackq; |
430 |
char lastc; |
|
|
431 |
int startloc = dest - stackblock(); |
568 |
int startloc = dest - stackblock(); |
432 |
char const *syntax = quoted? DQSYNTAX : BASESYNTAX; |
569 |
char const *syntax = quoted? DQSYNTAX : BASESYNTAX; |
433 |
int saveherefd; |
570 |
int saveherefd; |
434 |
int quotes = flag & (EXP_FULL | EXP_CASE); |
|
|
435 |
|
571 |
|
436 |
INTOFF; |
572 |
in.fd = -1; |
|
|
573 |
in.buf = 0; |
574 |
in.jp = 0; |
575 |
|
437 |
saveifs = ifsfirst; |
576 |
saveifs = ifsfirst; |
438 |
savelastp = ifslastp; |
577 |
savelastp = ifslastp; |
439 |
saveargbackq = argbackq; |
578 |
saveargbackq = argbackq; |
440 |
saveherefd = herefd; |
579 |
saveherefd = herefd; |
441 |
herefd = -1; |
580 |
herefd = -1; |
442 |
p = grabstackstr(dest); |
581 |
|
443 |
evalbackcmd(cmd, &in); |
582 |
INTOFF; |
444 |
ungrabstackstr(p, dest); |
583 |
evalbackcmd(cmd, (struct backcmd *) &in); |
445 |
ifsfirst = saveifs; |
584 |
ifsfirst = saveifs; |
446 |
ifslastp = savelastp; |
585 |
ifslastp = savelastp; |
447 |
argbackq = saveargbackq; |
586 |
argbackq = saveargbackq; |
448 |
herefd = saveherefd; |
587 |
herefd = saveherefd; |
449 |
|
588 |
|
450 |
p = in.buf; |
589 |
p = in.buf; |
451 |
lastc = '\0'; |
590 |
i = in.nleft; |
|
|
591 |
if (i == 0) |
592 |
goto read; |
452 |
for (;;) { |
593 |
for (;;) { |
453 |
if (--in.nleft < 0) { |
594 |
memtodest(p, i, syntax, quotes); |
|
|
595 |
read: |
454 |
if (in.fd < 0) |
596 |
if (in.fd < 0) |
455 |
break; |
597 |
break; |
456 |
while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); |
598 |
while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); |
Lines 458-475
Link Here
|
458 |
if (i <= 0) |
600 |
if (i <= 0) |
459 |
break; |
601 |
break; |
460 |
p = buf; |
602 |
p = buf; |
461 |
in.nleft = i - 1; |
|
|
462 |
} |
463 |
lastc = *p++; |
464 |
if (lastc != '\0') { |
465 |
if (quotes && syntax[(int)lastc] == CCTL) |
466 |
STPUTC(CTLESC, dest); |
467 |
STPUTC(lastc, dest); |
468 |
} |
469 |
} |
603 |
} |
470 |
|
604 |
|
|
|
605 |
dest = expdest; |
606 |
|
471 |
/* Eat all trailing newlines */ |
607 |
/* Eat all trailing newlines */ |
472 |
for (p--; lastc == '\n'; lastc = *--p) |
608 |
for (; dest > stackblock() && dest[-1] == '\n';) |
473 |
STUNPUTC(dest); |
609 |
STUNPUTC(dest); |
474 |
|
610 |
|
475 |
if (in.fd >= 0) |
611 |
if (in.fd >= 0) |
Lines 478-483
Link Here
|
478 |
ckfree(in.buf); |
614 |
ckfree(in.buf); |
479 |
if (in.jp) |
615 |
if (in.jp) |
480 |
exitstatus = waitforjob(in.jp); |
616 |
exitstatus = waitforjob(in.jp); |
|
|
617 |
INTON; |
481 |
if (quoted == 0) |
618 |
if (quoted == 0) |
482 |
recordregion(startloc, dest - stackblock(), 0); |
619 |
recordregion(startloc, dest - stackblock(), 0); |
483 |
TRACE(("evalbackq: size=%d: \"%.*s\"\n", |
620 |
TRACE(("evalbackq: size=%d: \"%.*s\"\n", |
Lines 485-615
Link Here
|
485 |
(dest - stackblock()) - startloc, |
622 |
(dest - stackblock()) - startloc, |
486 |
stackblock() + startloc)); |
623 |
stackblock() + startloc)); |
487 |
expdest = dest; |
624 |
expdest = dest; |
488 |
INTON; |
|
|
489 |
} |
625 |
} |
490 |
|
626 |
|
491 |
|
627 |
|
|
|
628 |
STATIC char * |
629 |
scanleft( |
630 |
char *startp, char *rmesc, char *rmescend, char *str, int quotes, |
631 |
int zero |
632 |
) { |
633 |
char *loc; |
634 |
char *loc2; |
635 |
char c; |
636 |
|
637 |
loc = startp; |
638 |
loc2 = rmesc; |
639 |
do { |
640 |
int match; |
641 |
const char *s = loc2; |
642 |
c = *loc2; |
643 |
if (zero) { |
644 |
*loc2 = '\0'; |
645 |
s = rmesc; |
646 |
} |
647 |
match = pmatch(str, s); |
648 |
*loc2 = c; |
649 |
if (match) |
650 |
return loc; |
651 |
if (quotes && *loc == CTLESC) |
652 |
loc++; |
653 |
loc++; |
654 |
loc2++; |
655 |
} while (c); |
656 |
return 0; |
657 |
} |
658 |
|
659 |
|
660 |
STATIC char * |
661 |
scanright( |
662 |
char *startp, char *rmesc, char *rmescend, char *str, int quotes, |
663 |
int zero |
664 |
) { |
665 |
int esc = 0; |
666 |
char *loc; |
667 |
char *loc2; |
492 |
|
668 |
|
493 |
STATIC int |
669 |
for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { |
494 |
subevalvar(p, str, strloc, subtype, startloc, varflags) |
670 |
int match; |
|
|
671 |
char c = *loc2; |
672 |
const char *s = loc2; |
673 |
if (zero) { |
674 |
*loc2 = '\0'; |
675 |
s = rmesc; |
676 |
} |
677 |
match = pmatch(str, s); |
678 |
*loc2 = c; |
679 |
if (match) |
680 |
return loc; |
681 |
loc--; |
682 |
if (quotes) { |
683 |
if (--esc < 0) { |
684 |
esc = esclen(startp, loc); |
685 |
} |
686 |
if (esc % 2) { |
687 |
esc--; |
688 |
loc--; |
689 |
} |
690 |
} |
691 |
} |
692 |
return 0; |
693 |
} |
694 |
|
695 |
STATIC const char * |
696 |
subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) |
495 |
char *p; |
697 |
char *p; |
496 |
char *str; |
698 |
char *str; |
497 |
int strloc; |
699 |
int strloc; |
498 |
int subtype; |
700 |
int subtype; |
499 |
int startloc; |
701 |
int startloc; |
500 |
int varflags; |
702 |
int varflags; |
|
|
703 |
int quotes; |
501 |
{ |
704 |
{ |
502 |
char *startp; |
705 |
char *startp; |
503 |
char *loc = NULL; |
706 |
char *loc; |
504 |
char *q; |
|
|
505 |
int c = 0; |
506 |
int saveherefd = herefd; |
707 |
int saveherefd = herefd; |
507 |
struct nodelist *saveargbackq = argbackq; |
708 |
struct nodelist *saveargbackq = argbackq; |
508 |
int amount; |
709 |
int amount; |
|
|
710 |
char *rmesc, *rmescend; |
711 |
int zero; |
712 |
char *(*scan)(char *, char *, char *, char *, int , int); |
509 |
|
713 |
|
510 |
herefd = -1; |
714 |
herefd = -1; |
511 |
argstr(p, 0); |
715 |
argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); |
512 |
STACKSTRNUL(expdest); |
716 |
STPUTC('\0', expdest); |
513 |
herefd = saveherefd; |
717 |
herefd = saveherefd; |
514 |
argbackq = saveargbackq; |
718 |
argbackq = saveargbackq; |
515 |
startp = stackblock() + startloc; |
719 |
startp = stackblock() + startloc; |
516 |
if (str == NULL) |
|
|
517 |
str = stackblock() + strloc; |
518 |
|
720 |
|
519 |
switch (subtype) { |
721 |
switch (subtype) { |
520 |
case VSASSIGN: |
722 |
case VSASSIGN: |
521 |
setvar(str, startp, 0); |
723 |
setvar(str, startp, 0); |
522 |
amount = startp - expdest; |
724 |
amount = startp - expdest; |
523 |
STADJUST(amount, expdest); |
725 |
STADJUST(amount, expdest); |
524 |
varflags &= ~VSNUL; |
726 |
return startp; |
525 |
if (c != 0) |
|
|
526 |
*loc = c; |
527 |
return 1; |
528 |
|
727 |
|
529 |
case VSQUESTION: |
728 |
case VSQUESTION: |
530 |
if (*p != CTLENDVAR) { |
729 |
varunset(p, str, startp, varflags); |
531 |
outfmt(&errout, "%s\n", startp); |
|
|
532 |
error((char *)NULL); |
533 |
} |
534 |
error("%.*s: parameter %snot set", p - str - 1, |
535 |
str, (varflags & VSNUL) ? "null or " |
536 |
: nullstr); |
537 |
/* NOTREACHED */ |
730 |
/* NOTREACHED */ |
538 |
|
|
|
539 |
case VSTRIMLEFT: |
540 |
for (loc = startp; loc < str; loc++) { |
541 |
c = *loc; |
542 |
*loc = '\0'; |
543 |
if (patmatch(str, startp, varflags & VSQUOTE)) |
544 |
goto recordleft; |
545 |
*loc = c; |
546 |
if ((varflags & VSQUOTE) && *loc == CTLESC) |
547 |
loc++; |
548 |
} |
731 |
} |
549 |
return 0; |
|
|
550 |
|
732 |
|
551 |
case VSTRIMLEFTMAX: |
733 |
subtype -= VSTRIMRIGHT; |
552 |
for (loc = str - 1; loc >= startp;) { |
734 |
#ifdef DEBUG |
553 |
c = *loc; |
735 |
if (subtype < 0 || subtype > 3) |
554 |
*loc = '\0'; |
736 |
abort(); |
555 |
if (patmatch(str, startp, varflags & VSQUOTE)) |
737 |
#endif |
556 |
goto recordleft; |
|
|
557 |
*loc = c; |
558 |
loc--; |
559 |
if ((varflags & VSQUOTE) && loc > startp && |
560 |
*(loc - 1) == CTLESC) { |
561 |
for (q = startp; q < loc; q++) |
562 |
if (*q == CTLESC) |
563 |
q++; |
564 |
if (q > loc) |
565 |
loc--; |
566 |
} |
567 |
} |
568 |
return 0; |
569 |
|
738 |
|
570 |
case VSTRIMRIGHT: |
739 |
rmesc = startp; |
571 |
for (loc = str - 1; loc >= startp;) { |
740 |
rmescend = stackblock() + strloc; |
572 |
if (patmatch(str, loc, varflags & VSQUOTE)) |
741 |
if (quotes) { |
573 |
goto recordright; |
742 |
rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); |
574 |
loc--; |
743 |
if (rmesc != startp) { |
575 |
if ((varflags & VSQUOTE) && loc > startp && |
744 |
rmescend = expdest; |
576 |
*(loc - 1) == CTLESC) { |
745 |
startp = stackblock() + startloc; |
577 |
for (q = startp; q < loc; q++) |
|
|
578 |
if (*q == CTLESC) |
579 |
q++; |
580 |
if (q > loc) |
581 |
loc--; |
582 |
} |
746 |
} |
583 |
} |
747 |
} |
584 |
return 0; |
748 |
rmescend--; |
|
|
749 |
str = stackblock() + strloc; |
750 |
preglob(str, varflags & VSQUOTE, 0); |
585 |
|
751 |
|
586 |
case VSTRIMRIGHTMAX: |
752 |
/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ |
587 |
for (loc = startp; loc < str - 1; loc++) { |
753 |
zero = subtype >> 1; |
588 |
if (patmatch(str, loc, varflags & VSQUOTE)) |
754 |
/* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ |
589 |
goto recordright; |
755 |
scan = (subtype & 1) ^ zero ? scanleft : scanright; |
590 |
if ((varflags & VSQUOTE) && *loc == CTLESC) |
|
|
591 |
loc++; |
592 |
} |
593 |
return 0; |
594 |
|
756 |
|
595 |
default: |
757 |
loc = scan(startp, rmesc, rmescend, str, quotes, zero); |
596 |
abort(); |
758 |
if (loc) { |
|
|
759 |
if (zero) { |
760 |
memmove(startp, loc, str - loc); |
761 |
loc = startp + (str - loc) - 1; |
597 |
} |
762 |
} |
598 |
|
763 |
*loc = '\0'; |
599 |
recordleft: |
|
|
600 |
*loc = c; |
601 |
amount = ((str - 1) - (loc - startp)) - expdest; |
602 |
STADJUST(amount, expdest); |
603 |
while (loc != str - 1) |
604 |
*startp++ = *loc++; |
605 |
return 1; |
606 |
|
607 |
recordright: |
608 |
amount = loc - expdest; |
764 |
amount = loc - expdest; |
609 |
STADJUST(amount, expdest); |
765 |
STADJUST(amount, expdest); |
610 |
STPUTC('\0', expdest); |
766 |
} |
611 |
STADJUST(-1, expdest); |
767 |
return loc; |
612 |
return 1; |
|
|
613 |
} |
768 |
} |
614 |
|
769 |
|
615 |
|
770 |
|
Lines 617-736
Link Here
|
617 |
* Expand a variable, and return a pointer to the next character in the |
772 |
* Expand a variable, and return a pointer to the next character in the |
618 |
* input string. |
773 |
* input string. |
619 |
*/ |
774 |
*/ |
620 |
|
|
|
621 |
STATIC char * |
775 |
STATIC char * |
622 |
evalvar(p, flag) |
776 |
evalvar(p, flag) |
623 |
char *p; |
777 |
char *p; |
624 |
int flag; |
778 |
const int flag; |
625 |
{ |
779 |
{ |
626 |
int subtype; |
780 |
int subtype; |
627 |
int varflags; |
781 |
int varflags; |
628 |
char *var; |
782 |
char *var; |
629 |
char *val; |
|
|
630 |
int patloc; |
783 |
int patloc; |
631 |
int c; |
784 |
int c; |
632 |
int set; |
785 |
int set; |
633 |
int special; |
|
|
634 |
int startloc; |
786 |
int startloc; |
635 |
int varlen; |
787 |
size_t varlen; |
636 |
int easy; |
788 |
int easy; |
637 |
int quotes = flag & (EXP_FULL | EXP_CASE); |
789 |
int quotes; |
|
|
790 |
int quoted; |
638 |
|
791 |
|
|
|
792 |
quotes = flag & (EXP_FULL | EXP_CASE); |
639 |
varflags = *p++; |
793 |
varflags = *p++; |
640 |
subtype = varflags & VSTYPE; |
794 |
subtype = varflags & VSTYPE; |
|
|
795 |
quoted = varflags & VSQUOTE; |
641 |
var = p; |
796 |
var = p; |
642 |
special = 0; |
797 |
easy = (!quoted || (*var == '@' && shellparam.nparam)); |
643 |
if (! is_name(*p)) |
|
|
644 |
special = 1; |
645 |
p = strchr(p, '=') + 1; |
646 |
again: /* jump here after setting a variable with ${var=text} */ |
647 |
if (special) { |
648 |
set = varisset(var, varflags & VSNUL); |
649 |
val = NULL; |
650 |
} else { |
651 |
val = lookupvar(var); |
652 |
if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { |
653 |
val = NULL; |
654 |
set = 0; |
655 |
} else |
656 |
set = 1; |
657 |
} |
658 |
varlen = 0; |
798 |
varlen = 0; |
659 |
startloc = expdest - stackblock(); |
799 |
startloc = expdest - stackblock(); |
660 |
if (!set && uflag) |
800 |
p = strchr(p, '=') + 1; |
661 |
switch (subtype) { |
801 |
|
662 |
case VSNORMAL: |
802 |
if (!is_name(*var)) { |
663 |
case VSTRIMLEFT: |
803 |
set = varisset(var, varflags & VSNUL); |
664 |
case VSTRIMLEFTMAX: |
804 |
set--; |
665 |
case VSTRIMRIGHT: |
805 |
if (subtype == VSPLUS) |
666 |
case VSTRIMRIGHTMAX: |
806 |
goto vsplus; |
667 |
case VSLENGTH: |
807 |
if (++set) { |
668 |
error("%.*s: parameter not set", p - var - 1, var); |
808 |
varvalue(var, quoted, flag); |
669 |
/* NOTREACHED */ |
|
|
670 |
} |
671 |
if (set && subtype != VSPLUS) { |
672 |
/* insert the value of the variable */ |
673 |
if (special) { |
674 |
varvalue(var, varflags & VSQUOTE, flag & EXP_FULL); |
675 |
if (subtype == VSLENGTH) { |
809 |
if (subtype == VSLENGTH) { |
676 |
varlen = expdest - stackblock() - startloc; |
810 |
varlen = expdest - stackblock() - startloc; |
677 |
STADJUST(-varlen, expdest); |
811 |
STADJUST(-varlen, expdest); |
|
|
812 |
goto vslen; |
813 |
} |
678 |
} |
814 |
} |
679 |
} else { |
815 |
} else { |
680 |
char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX |
816 |
const char *val; |
681 |
: BASESYNTAX; |
817 |
again: |
|
|
818 |
/* jump here after setting a variable with ${var=text} */ |
819 |
val = lookupvar(var); |
820 |
set = !val || ((varflags & VSNUL) && !*val); |
821 |
if (subtype == VSPLUS) |
822 |
goto vsplus; |
823 |
if (--set) { |
824 |
varlen = strlen(val); |
825 |
if (subtype == VSLENGTH) |
826 |
goto vslen; |
827 |
memtodest( |
828 |
val, varlen, quoted ? DQSYNTAX : BASESYNTAX, |
829 |
quotes |
830 |
); |
831 |
} |
832 |
} |
682 |
|
833 |
|
683 |
if (subtype == VSLENGTH) { |
834 |
|
684 |
for (;*val; val++) |
835 |
if (subtype == VSMINUS) { |
685 |
varlen++; |
836 |
vsplus: |
|
|
837 |
if (!set) { |
838 |
argstr( |
839 |
p, flag | EXP_TILDE | |
840 |
(quoted ? EXP_QWORD : EXP_WORD) |
841 |
); |
842 |
goto end; |
686 |
} |
843 |
} |
687 |
else { |
844 |
if (easy) |
688 |
while (*val) { |
845 |
goto record; |
689 |
if (quotes && syntax[(int)*val] == CCTL) |
846 |
goto end; |
690 |
STPUTC(CTLESC, expdest); |
|
|
691 |
STPUTC(*val++, expdest); |
692 |
} |
847 |
} |
693 |
|
848 |
|
|
|
849 |
if (subtype == VSASSIGN || subtype == VSQUESTION) { |
850 |
if (!set) { |
851 |
if (subevalvar(p, var, 0, subtype, startloc, |
852 |
varflags, 0)) { |
853 |
varflags &= ~VSNUL; |
854 |
/* |
855 |
* Remove any recorded regions beyond |
856 |
* start of variable |
857 |
*/ |
858 |
removerecordregions(startloc); |
859 |
goto again; |
694 |
} |
860 |
} |
|
|
861 |
goto end; |
695 |
} |
862 |
} |
|
|
863 |
if (easy) |
864 |
goto record; |
865 |
goto end; |
696 |
} |
866 |
} |
697 |
|
867 |
|
698 |
if (subtype == VSPLUS) |
868 |
if (!set && uflag) |
699 |
set = ! set; |
869 |
varunset(p, var, 0, 0); |
700 |
|
|
|
701 |
easy = ((varflags & VSQUOTE) == 0 || |
702 |
(*var == '@' && shellparam.nparam != 1)); |
703 |
|
704 |
|
870 |
|
705 |
switch (subtype) { |
871 |
if (subtype == VSLENGTH) { |
706 |
case VSLENGTH: |
872 |
vslen: |
707 |
expdest = cvtnum(varlen, expdest); |
873 |
cvtnum(varlen); |
708 |
goto record; |
874 |
goto record; |
|
|
875 |
} |
709 |
|
876 |
|
710 |
case VSNORMAL: |
877 |
if (subtype == VSNORMAL) { |
711 |
if (!easy) |
878 |
if (!easy) |
712 |
break; |
879 |
goto end; |
713 |
record: |
880 |
record: |
714 |
recordregion(startloc, expdest - stackblock(), |
881 |
recordregion(startloc, expdest - stackblock(), quoted); |
715 |
varflags & VSQUOTE); |
882 |
goto end; |
716 |
break; |
|
|
717 |
|
718 |
case VSPLUS: |
719 |
case VSMINUS: |
720 |
if (!set) { |
721 |
argstr(p, flag); |
722 |
break; |
723 |
} |
883 |
} |
724 |
if (easy) |
|
|
725 |
goto record; |
726 |
break; |
727 |
|
884 |
|
|
|
885 |
#ifdef DEBUG |
886 |
switch (subtype) { |
728 |
case VSTRIMLEFT: |
887 |
case VSTRIMLEFT: |
729 |
case VSTRIMLEFTMAX: |
888 |
case VSTRIMLEFTMAX: |
730 |
case VSTRIMRIGHT: |
889 |
case VSTRIMRIGHT: |
731 |
case VSTRIMRIGHTMAX: |
890 |
case VSTRIMRIGHTMAX: |
732 |
if (!set) |
|
|
733 |
break; |
891 |
break; |
|
|
892 |
default: |
893 |
abort(); |
894 |
} |
895 |
#endif |
896 |
|
897 |
if (set) { |
734 |
/* |
898 |
/* |
735 |
* Terminate the string and start recording the pattern |
899 |
* Terminate the string and start recording the pattern |
736 |
* right after it |
900 |
* right after it |
Lines 738-774
Link Here
|
738 |
STPUTC('\0', expdest); |
902 |
STPUTC('\0', expdest); |
739 |
patloc = expdest - stackblock(); |
903 |
patloc = expdest - stackblock(); |
740 |
if (subevalvar(p, NULL, patloc, subtype, |
904 |
if (subevalvar(p, NULL, patloc, subtype, |
741 |
startloc, varflags) == 0) { |
905 |
startloc, varflags, quotes) == 0) { |
742 |
int amount = (expdest - stackblock() - patloc) + 1; |
906 |
int amount = expdest - (stackblock() + patloc - 1); |
743 |
STADJUST(-amount, expdest); |
907 |
STADJUST(-amount, expdest); |
744 |
} |
908 |
} |
745 |
/* Remove any recorded regions beyond start of variable */ |
909 |
/* Remove any recorded regions beyond start of variable */ |
746 |
removerecordregions(startloc); |
910 |
removerecordregions(startloc); |
747 |
goto record; |
911 |
goto record; |
748 |
|
|
|
749 |
case VSASSIGN: |
750 |
case VSQUESTION: |
751 |
if (!set) { |
752 |
if (subevalvar(p, var, 0, subtype, startloc, |
753 |
varflags)) { |
754 |
varflags &= ~VSNUL; |
755 |
/* |
756 |
* Remove any recorded regions beyond |
757 |
* start of variable |
758 |
*/ |
759 |
removerecordregions(startloc); |
760 |
goto again; |
761 |
} |
762 |
break; |
763 |
} |
764 |
if (easy) |
765 |
goto record; |
766 |
break; |
767 |
|
768 |
default: |
769 |
abort(); |
770 |
} |
912 |
} |
771 |
|
913 |
|
|
|
914 |
end: |
772 |
if (subtype != VSNORMAL) { /* skip to end of alternative */ |
915 |
if (subtype != VSNORMAL) { /* skip to end of alternative */ |
773 |
int nesting = 1; |
916 |
int nesting = 1; |
774 |
for (;;) { |
917 |
for (;;) { |
Lines 801-807
Link Here
|
801 |
int nulok; |
944 |
int nulok; |
802 |
{ |
945 |
{ |
803 |
if (*name == '!') |
946 |
if (*name == '!') |
804 |
return backgndpid != -1; |
947 |
return backgndpid != 0; |
805 |
else if (*name == '@' || *name == '*') { |
948 |
else if (*name == '@' || *name == '*') { |
806 |
if (*shellparam.p == NULL) |
949 |
if (*shellparam.p == NULL) |
807 |
return 0; |
950 |
return 0; |
Lines 835-871
Link Here
|
835 |
|
978 |
|
836 |
|
979 |
|
837 |
/* |
980 |
/* |
|
|
981 |
* Put a string on the stack. |
982 |
*/ |
983 |
|
984 |
STATIC void |
985 |
memtodest(const char *p, size_t len, const char *syntax, int quotes) { |
986 |
char *q = expdest; |
987 |
|
988 |
q = makestrspace(len * 2, q); |
989 |
|
990 |
while (len--) { |
991 |
int c = *p++; |
992 |
if (!c) |
993 |
continue; |
994 |
if (quotes && (syntax[c] == CCTL || syntax[c] == CBACK)) |
995 |
USTPUTC(CTLESC, q); |
996 |
USTPUTC(c, q); |
997 |
} |
998 |
|
999 |
expdest = q; |
1000 |
} |
1001 |
|
1002 |
|
1003 |
STATIC void |
1004 |
strtodest(p, syntax, quotes) |
1005 |
const char *p; |
1006 |
const char *syntax; |
1007 |
int quotes; |
1008 |
{ |
1009 |
memtodest(p, strlen(p), syntax, quotes); |
1010 |
} |
1011 |
|
1012 |
|
1013 |
|
1014 |
/* |
838 |
* Add the value of a specialized variable to the stack string. |
1015 |
* Add the value of a specialized variable to the stack string. |
839 |
*/ |
1016 |
*/ |
840 |
|
1017 |
|
841 |
STATIC void |
1018 |
STATIC void |
842 |
varvalue(name, quoted, allow_split) |
1019 |
varvalue(name, quoted, flags) |
843 |
char *name; |
1020 |
char *name; |
844 |
int quoted; |
1021 |
int quoted; |
845 |
int allow_split; |
1022 |
int flags; |
846 |
{ |
1023 |
{ |
847 |
int num; |
1024 |
int num; |
848 |
char *p; |
1025 |
char *p; |
849 |
int i; |
1026 |
int i; |
850 |
char sep; |
1027 |
int sep; |
|
|
1028 |
int sepq = 0; |
851 |
char **ap; |
1029 |
char **ap; |
852 |
char const *syntax; |
1030 |
char const *syntax; |
|
|
1031 |
int allow_split = flags & EXP_FULL; |
1032 |
int quotes = flags & (EXP_FULL | EXP_CASE); |
853 |
|
1033 |
|
854 |
#define STRTODEST(p) \ |
1034 |
syntax = quoted ? DQSYNTAX : BASESYNTAX; |
855 |
do {\ |
|
|
856 |
if (allow_split) { \ |
857 |
syntax = quoted? DQSYNTAX : BASESYNTAX; \ |
858 |
while (*p) { \ |
859 |
if (syntax[(int)*p] == CCTL) \ |
860 |
STPUTC(CTLESC, expdest); \ |
861 |
STPUTC(*p++, expdest); \ |
862 |
} \ |
863 |
} else \ |
864 |
while (*p) \ |
865 |
STPUTC(*p++, expdest); \ |
866 |
} while (0) |
867 |
|
868 |
|
869 |
switch (*name) { |
1035 |
switch (*name) { |
870 |
case '$': |
1036 |
case '$': |
871 |
num = rootpid; |
1037 |
num = rootpid; |
Lines 879-924
Link Here
|
879 |
case '!': |
1045 |
case '!': |
880 |
num = backgndpid; |
1046 |
num = backgndpid; |
881 |
numvar: |
1047 |
numvar: |
882 |
expdest = cvtnum(num, expdest); |
1048 |
cvtnum(num); |
883 |
break; |
1049 |
break; |
884 |
case '-': |
1050 |
case '-': |
885 |
for (i = 0 ; i < NOPTS ; i++) { |
1051 |
for (i = 0 ; i < NOPTS ; i++) { |
886 |
if (optlist[i].val) |
1052 |
if (optlist[i]) |
887 |
STPUTC(optlist[i].letter, expdest); |
1053 |
STPUTC(optletters[i], expdest); |
888 |
} |
1054 |
} |
889 |
break; |
1055 |
break; |
890 |
case '@': |
1056 |
case '@': |
891 |
if (allow_split && quoted) { |
1057 |
if (allow_split && quoted) { |
892 |
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { |
1058 |
sep = 1 << CHAR_BIT; |
893 |
STRTODEST(p); |
1059 |
goto param; |
894 |
if (*ap) |
|
|
895 |
STPUTC('\0', expdest); |
896 |
} |
897 |
break; |
898 |
} |
1060 |
} |
899 |
/* fall through */ |
1061 |
/* fall through */ |
900 |
case '*': |
1062 |
case '*': |
901 |
if (ifsset() != 0) |
1063 |
sep = ifsset() ? ifsval()[0] : ' '; |
902 |
sep = ifsval()[0]; |
1064 |
if (quotes) { |
903 |
else |
1065 |
sepq = (syntax[sep] == CCTL) || (syntax[sep] == CBACK); |
904 |
sep = ' '; |
1066 |
} |
|
|
1067 |
param: |
905 |
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { |
1068 |
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { |
906 |
STRTODEST(p); |
1069 |
strtodest(p, syntax, quotes); |
907 |
if (*ap && sep) |
1070 |
if (*ap && sep) { |
908 |
STPUTC(sep, expdest); |
1071 |
p = expdest; |
|
|
1072 |
if (sepq) |
1073 |
STPUTC(CTLESC, p); |
1074 |
STPUTC(sep, p); |
1075 |
expdest = p; |
1076 |
} |
909 |
} |
1077 |
} |
910 |
break; |
1078 |
break; |
911 |
case '0': |
1079 |
case '0': |
912 |
p = arg0; |
1080 |
strtodest(arg0, syntax, quotes); |
913 |
STRTODEST(p); |
|
|
914 |
break; |
1081 |
break; |
915 |
default: |
1082 |
default: |
916 |
if (is_digit(*name)) { |
|
|
917 |
num = atoi(name); |
1083 |
num = atoi(name); |
918 |
if (num > 0 && num <= shellparam.nparam) { |
1084 |
if (num > 0 && num <= shellparam.nparam) { |
919 |
p = shellparam.p[num - 1]; |
1085 |
strtodest(shellparam.p[num - 1], syntax, quotes); |
920 |
STRTODEST(p); |
|
|
921 |
} |
922 |
} |
1086 |
} |
923 |
break; |
1087 |
break; |
924 |
} |
1088 |
} |
Lines 942-952
Link Here
|
942 |
if (ifslastp == NULL) { |
1106 |
if (ifslastp == NULL) { |
943 |
ifsp = &ifsfirst; |
1107 |
ifsp = &ifsfirst; |
944 |
} else { |
1108 |
} else { |
|
|
1109 |
INTOFF; |
945 |
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); |
1110 |
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); |
|
|
1111 |
ifsp->next = NULL; |
946 |
ifslastp->next = ifsp; |
1112 |
ifslastp->next = ifsp; |
|
|
1113 |
INTON; |
947 |
} |
1114 |
} |
948 |
ifslastp = ifsp; |
1115 |
ifslastp = ifsp; |
949 |
ifslastp->next = NULL; |
|
|
950 |
ifslastp->begoff = start; |
1116 |
ifslastp->begoff = start; |
951 |
ifslastp->endoff = end; |
1117 |
ifslastp->endoff = end; |
952 |
ifslastp->nulonly = nulonly; |
1118 |
ifslastp->nulonly = nulonly; |
Lines 969-975
Link Here
|
969 |
char *start; |
1135 |
char *start; |
970 |
char *p; |
1136 |
char *p; |
971 |
char *q; |
1137 |
char *q; |
972 |
const char *ifs; |
1138 |
const char *ifs, *realifs; |
973 |
int ifsspc; |
1139 |
int ifsspc; |
974 |
int nulonly; |
1140 |
int nulonly; |
975 |
|
1141 |
|
Lines 977-989
Link Here
|
977 |
start = string; |
1143 |
start = string; |
978 |
ifsspc = 0; |
1144 |
ifsspc = 0; |
979 |
nulonly = 0; |
1145 |
nulonly = 0; |
|
|
1146 |
realifs = ifsset() ? ifsval() : defifs; |
980 |
if (ifslastp != NULL) { |
1147 |
if (ifslastp != NULL) { |
981 |
ifsp = &ifsfirst; |
1148 |
ifsp = &ifsfirst; |
982 |
do { |
1149 |
do { |
983 |
p = string + ifsp->begoff; |
1150 |
p = string + ifsp->begoff; |
984 |
nulonly = ifsp->nulonly; |
1151 |
nulonly = ifsp->nulonly; |
985 |
ifs = nulonly ? nullstr : |
1152 |
ifs = nulonly ? nullstr : realifs; |
986 |
( ifsset() ? ifsval() : " \t\n" ); |
|
|
987 |
ifsspc = 0; |
1153 |
ifsspc = 0; |
988 |
while (p < string + ifsp->endoff) { |
1154 |
while (p < string + ifsp->endoff) { |
989 |
q = p; |
1155 |
q = p; |
Lines 991-997
Link Here
|
991 |
p++; |
1157 |
p++; |
992 |
if (strchr(ifs, *p)) { |
1158 |
if (strchr(ifs, *p)) { |
993 |
if (!nulonly) |
1159 |
if (!nulonly) |
994 |
ifsspc = (strchr(" \t\n", *p) != NULL); |
1160 |
ifsspc = (strchr(defifs, *p) != NULL); |
995 |
/* Ignore IFS whitespace at start */ |
1161 |
/* Ignore IFS whitespace at start */ |
996 |
if (q == start && ifsspc) { |
1162 |
if (q == start && ifsspc) { |
997 |
p++; |
1163 |
p++; |
Lines 1015-1021
Link Here
|
1015 |
if (strchr(ifs, *p) == NULL ) { |
1181 |
if (strchr(ifs, *p) == NULL ) { |
1016 |
p = q; |
1182 |
p = q; |
1017 |
break; |
1183 |
break; |
1018 |
} else if (strchr(" \t\n",*p) == NULL) { |
1184 |
} else if (strchr(defifs, *p) == NULL) { |
1019 |
if (ifsspc) { |
1185 |
if (ifsspc) { |
1020 |
p++; |
1186 |
p++; |
1021 |
ifsspc = 0; |
1187 |
ifsspc = 0; |
Lines 1032-1050
Link Here
|
1032 |
p++; |
1198 |
p++; |
1033 |
} |
1199 |
} |
1034 |
} while ((ifsp = ifsp->next) != NULL); |
1200 |
} while ((ifsp = ifsp->next) != NULL); |
1035 |
if (*start || (!ifsspc && start > string && |
1201 |
if (nulonly) |
1036 |
(nulonly || 1))) { |
1202 |
goto add; |
1037 |
sp = (struct strlist *)stalloc(sizeof *sp); |
|
|
1038 |
sp->text = start; |
1039 |
*arglist->lastp = sp; |
1040 |
arglist->lastp = &sp->next; |
1041 |
} |
1203 |
} |
1042 |
} else { |
1204 |
|
|
|
1205 |
if (!*start) |
1206 |
return; |
1207 |
|
1208 |
add: |
1043 |
sp = (struct strlist *)stalloc(sizeof *sp); |
1209 |
sp = (struct strlist *)stalloc(sizeof *sp); |
1044 |
sp->text = start; |
1210 |
sp->text = start; |
1045 |
*arglist->lastp = sp; |
1211 |
*arglist->lastp = sp; |
1046 |
arglist->lastp = &sp->next; |
1212 |
arglist->lastp = &sp->next; |
1047 |
} |
|
|
1048 |
} |
1213 |
} |
1049 |
|
1214 |
|
1050 |
STATIC void |
1215 |
STATIC void |
Lines 1069-1075
Link Here
|
1069 |
* should be escapes. The results are stored in the list exparg. |
1234 |
* should be escapes. The results are stored in the list exparg. |
1070 |
*/ |
1235 |
*/ |
1071 |
|
1236 |
|
1072 |
char *expdir; |
1237 |
#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) |
|
|
1238 |
STATIC void |
1239 |
expandmeta(str, flag) |
1240 |
struct strlist *str; |
1241 |
int flag; |
1242 |
{ |
1243 |
/* TODO - EXP_REDIR */ |
1244 |
|
1245 |
while (str) { |
1246 |
const char *p; |
1247 |
glob_t pglob; |
1248 |
int i; |
1249 |
|
1250 |
if (fflag) |
1251 |
goto nometa; |
1252 |
INTOFF; |
1253 |
p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
1254 |
i = glob(p, GLOB_NOMAGIC, 0, &pglob); |
1255 |
if (p != str->text) |
1256 |
ckfree(p); |
1257 |
switch (i) { |
1258 |
case 0: |
1259 |
if (!(pglob.gl_flags & GLOB_MAGCHAR)) |
1260 |
goto nometa2; |
1261 |
addglob(&pglob); |
1262 |
globfree(&pglob); |
1263 |
INTON; |
1264 |
break; |
1265 |
case GLOB_NOMATCH: |
1266 |
nometa2: |
1267 |
globfree(&pglob); |
1268 |
INTON; |
1269 |
nometa: |
1270 |
*exparg.lastp = str; |
1271 |
rmescapes(str->text); |
1272 |
exparg.lastp = &str->next; |
1273 |
break; |
1274 |
default: /* GLOB_NOSPACE */ |
1275 |
error("Out of space"); |
1276 |
} |
1277 |
str = str->next; |
1278 |
} |
1279 |
} |
1280 |
|
1281 |
|
1282 |
/* |
1283 |
* Add the result of glob(3) to the list. |
1284 |
*/ |
1285 |
|
1286 |
STATIC void |
1287 |
addglob(pglob) |
1288 |
const glob_t *pglob; |
1289 |
{ |
1290 |
char **p = pglob->gl_pathv; |
1291 |
|
1292 |
do { |
1293 |
addfname(*p); |
1294 |
} while (*++p); |
1295 |
} |
1296 |
|
1297 |
|
1298 |
#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ |
1299 |
STATIC char *expdir; |
1073 |
|
1300 |
|
1074 |
|
1301 |
|
1075 |
STATIC void |
1302 |
STATIC void |
Lines 1077-1108
Link Here
|
1077 |
struct strlist *str; |
1304 |
struct strlist *str; |
1078 |
int flag; |
1305 |
int flag; |
1079 |
{ |
1306 |
{ |
1080 |
char *p; |
1307 |
static const char metachars[] = { |
1081 |
struct strlist **savelastp; |
1308 |
'*', '?', '[', 0 |
1082 |
struct strlist *sp; |
1309 |
}; |
1083 |
char c; |
|
|
1084 |
/* TODO - EXP_REDIR */ |
1310 |
/* TODO - EXP_REDIR */ |
1085 |
|
1311 |
|
1086 |
while (str) { |
1312 |
while (str) { |
|
|
1313 |
struct strlist **savelastp; |
1314 |
struct strlist *sp; |
1315 |
char *p; |
1316 |
|
1087 |
if (fflag) |
1317 |
if (fflag) |
1088 |
goto nometa; |
1318 |
goto nometa; |
1089 |
p = str->text; |
1319 |
if (!strpbrk(str->text, metachars)) |
1090 |
for (;;) { /* fast check for meta chars */ |
|
|
1091 |
if ((c = *p++) == '\0') |
1092 |
goto nometa; |
1320 |
goto nometa; |
1093 |
if (c == '*' || c == '?' || c == '[' || c == '!') |
|
|
1094 |
break; |
1095 |
} |
1096 |
savelastp = exparg.lastp; |
1321 |
savelastp = exparg.lastp; |
|
|
1322 |
|
1097 |
INTOFF; |
1323 |
INTOFF; |
1098 |
if (expdir == NULL) { |
1324 |
p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
|
|
1325 |
{ |
1099 |
int i = strlen(str->text); |
1326 |
int i = strlen(str->text); |
1100 |
expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
1327 |
expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
1101 |
} |
1328 |
} |
1102 |
|
1329 |
|
1103 |
expmeta(expdir, str->text); |
1330 |
expmeta(expdir, p); |
1104 |
ckfree(expdir); |
1331 |
ckfree(expdir); |
1105 |
expdir = NULL; |
1332 |
if (p != str->text) |
|
|
1333 |
ckfree(p); |
1106 |
INTON; |
1334 |
INTON; |
1107 |
if (exparg.lastp == savelastp) { |
1335 |
if (exparg.lastp == savelastp) { |
1108 |
/* |
1336 |
/* |
Lines 1135-1145
Link Here
|
1135 |
{ |
1363 |
{ |
1136 |
char *p; |
1364 |
char *p; |
1137 |
const char *cp; |
1365 |
const char *cp; |
1138 |
char *q; |
|
|
1139 |
char *start; |
1366 |
char *start; |
1140 |
char *endname; |
1367 |
char *endname; |
1141 |
int metaflag; |
1368 |
int metaflag; |
1142 |
struct stat statb; |
1369 |
struct stat64 statb; |
1143 |
DIR *dirp; |
1370 |
DIR *dirp; |
1144 |
struct dirent *dp; |
1371 |
struct dirent *dp; |
1145 |
int atend; |
1372 |
int atend; |
Lines 1147-1163
Link Here
|
1147 |
|
1374 |
|
1148 |
metaflag = 0; |
1375 |
metaflag = 0; |
1149 |
start = name; |
1376 |
start = name; |
1150 |
for (p = name ; ; p++) { |
1377 |
for (p = name; *p; p++) { |
1151 |
if (*p == '*' || *p == '?') |
1378 |
if (*p == '*' || *p == '?') |
1152 |
metaflag = 1; |
1379 |
metaflag = 1; |
1153 |
else if (*p == '[') { |
1380 |
else if (*p == '[') { |
1154 |
q = p + 1; |
1381 |
char *q = p + 1; |
1155 |
if (*q == '!') |
1382 |
if (*q == '!') |
1156 |
q++; |
1383 |
q++; |
1157 |
for (;;) { |
1384 |
for (;;) { |
1158 |
while (*q == CTLQUOTEMARK) |
1385 |
if (*q == '\\') |
1159 |
q++; |
|
|
1160 |
if (*q == CTLESC) |
1161 |
q++; |
1386 |
q++; |
1162 |
if (*q == '/' || *q == '\0') |
1387 |
if (*q == '/' || *q == '\0') |
1163 |
break; |
1388 |
break; |
Lines 1166-1211
Link Here
|
1166 |
break; |
1391 |
break; |
1167 |
} |
1392 |
} |
1168 |
} |
1393 |
} |
1169 |
} else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { |
1394 |
} else if (*p == '\\') |
1170 |
metaflag = 1; |
|
|
1171 |
} else if (*p == '\0') |
1172 |
break; |
1173 |
else if (*p == CTLQUOTEMARK) |
1174 |
continue; |
1175 |
else if (*p == CTLESC) |
1176 |
p++; |
1395 |
p++; |
1177 |
if (*p == '/') { |
1396 |
else if (*p == '/') { |
1178 |
if (metaflag) |
1397 |
if (metaflag) |
1179 |
break; |
1398 |
goto out; |
1180 |
start = p + 1; |
1399 |
start = p + 1; |
1181 |
} |
1400 |
} |
1182 |
} |
1401 |
} |
|
|
1402 |
out: |
1183 |
if (metaflag == 0) { /* we've reached the end of the file name */ |
1403 |
if (metaflag == 0) { /* we've reached the end of the file name */ |
1184 |
if (enddir != expdir) |
1404 |
if (enddir != expdir) |
1185 |
metaflag++; |
1405 |
metaflag++; |
1186 |
for (p = name ; ; p++) { |
1406 |
p = name; |
1187 |
if (*p == CTLQUOTEMARK) |
1407 |
do { |
1188 |
continue; |
1408 |
if (*p == '\\') |
1189 |
if (*p == CTLESC) |
|
|
1190 |
p++; |
1409 |
p++; |
1191 |
*enddir++ = *p; |
1410 |
*enddir++ = *p; |
1192 |
if (*p == '\0') |
1411 |
} while (*p++); |
1193 |
break; |
1412 |
if (metaflag == 0 || lstat64(expdir, &statb) >= 0) |
1194 |
} |
|
|
1195 |
if (metaflag == 0 || lstat(expdir, &statb) >= 0) |
1196 |
addfname(expdir); |
1413 |
addfname(expdir); |
1197 |
return; |
1414 |
return; |
1198 |
} |
1415 |
} |
1199 |
endname = p; |
1416 |
endname = p; |
1200 |
if (start != name) { |
1417 |
if (name < start) { |
1201 |
p = name; |
1418 |
p = name; |
1202 |
while (p < start) { |
1419 |
do { |
1203 |
while (*p == CTLQUOTEMARK) |
1420 |
if (*p == '\\') |
1204 |
p++; |
|
|
1205 |
if (*p == CTLESC) |
1206 |
p++; |
1421 |
p++; |
1207 |
*enddir++ = *p++; |
1422 |
*enddir++ = *p++; |
1208 |
} |
1423 |
} while (p < start); |
1209 |
} |
1424 |
} |
1210 |
if (enddir == expdir) { |
1425 |
if (enddir == expdir) { |
1211 |
cp = "."; |
1426 |
cp = "."; |
Lines 1227-1242
Link Here
|
1227 |
} |
1442 |
} |
1228 |
matchdot = 0; |
1443 |
matchdot = 0; |
1229 |
p = start; |
1444 |
p = start; |
1230 |
while (*p == CTLQUOTEMARK) |
1445 |
if (*p == '\\') |
1231 |
p++; |
|
|
1232 |
if (*p == CTLESC) |
1233 |
p++; |
1446 |
p++; |
1234 |
if (*p == '.') |
1447 |
if (*p == '.') |
1235 |
matchdot++; |
1448 |
matchdot++; |
1236 |
while (! int_pending() && (dp = readdir(dirp)) != NULL) { |
1449 |
while (! int_pending() && (dp = readdir(dirp)) != NULL) { |
1237 |
if (dp->d_name[0] == '.' && ! matchdot) |
1450 |
if (dp->d_name[0] == '.' && ! matchdot) |
1238 |
continue; |
1451 |
continue; |
1239 |
if (patmatch(start, dp->d_name, 0)) { |
1452 |
if (pmatch(start, dp->d_name)) { |
1240 |
if (atend) { |
1453 |
if (atend) { |
1241 |
scopy(dp->d_name, enddir); |
1454 |
scopy(dp->d_name, enddir); |
1242 |
addfname(expdir); |
1455 |
addfname(expdir); |
Lines 1253-1258
Link Here
|
1253 |
if (! atend) |
1466 |
if (! atend) |
1254 |
endname[-1] = '/'; |
1467 |
endname[-1] = '/'; |
1255 |
} |
1468 |
} |
|
|
1469 |
#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ |
1256 |
|
1470 |
|
1257 |
|
1471 |
|
1258 |
/* |
1472 |
/* |
Lines 1263-1280
Link Here
|
1263 |
addfname(name) |
1477 |
addfname(name) |
1264 |
char *name; |
1478 |
char *name; |
1265 |
{ |
1479 |
{ |
1266 |
char *p; |
|
|
1267 |
struct strlist *sp; |
1480 |
struct strlist *sp; |
1268 |
|
1481 |
|
1269 |
p = stalloc(strlen(name) + 1); |
|
|
1270 |
scopy(name, p); |
1271 |
sp = (struct strlist *)stalloc(sizeof *sp); |
1482 |
sp = (struct strlist *)stalloc(sizeof *sp); |
1272 |
sp->text = p; |
1483 |
sp->text = sstrdup(name); |
1273 |
*exparg.lastp = sp; |
1484 |
*exparg.lastp = sp; |
1274 |
exparg.lastp = &sp->next; |
1485 |
exparg.lastp = &sp->next; |
1275 |
} |
1486 |
} |
1276 |
|
1487 |
|
1277 |
|
1488 |
|
|
|
1489 |
#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) |
1278 |
/* |
1490 |
/* |
1279 |
* Sort the results of file name expansion. It calculates the number of |
1491 |
* Sort the results of file name expansion. It calculates the number of |
1280 |
* strings to sort and then calls msort (short for merge sort) to do the |
1492 |
* strings to sort and then calls msort (short for merge sort) to do the |
Lines 1336-1370
Link Here
|
1336 |
} |
1548 |
} |
1337 |
return list; |
1549 |
return list; |
1338 |
} |
1550 |
} |
1339 |
|
1551 |
#endif |
1340 |
|
1552 |
|
1341 |
|
1553 |
|
1342 |
/* |
1554 |
/* |
1343 |
* Returns true if the pattern matches the string. |
1555 |
* Returns true if the pattern matches the string. |
1344 |
*/ |
1556 |
*/ |
1345 |
|
1557 |
|
1346 |
int |
1558 |
STATIC inline int |
1347 |
patmatch(pattern, string, squoted) |
1559 |
patmatch(pattern, string) |
1348 |
char *pattern; |
1560 |
char *pattern; |
1349 |
char *string; |
1561 |
const char *string; |
1350 |
int squoted; /* string might have quote chars */ |
|
|
1351 |
{ |
1562 |
{ |
1352 |
#ifdef notdef |
1563 |
return pmatch(preglob(pattern, 0, 0), string); |
1353 |
if (pattern[0] == '!' && pattern[1] == '!') |
|
|
1354 |
return 1 - pmatch(pattern + 2, string); |
1355 |
else |
1356 |
#endif |
1357 |
return pmatch(pattern, string, squoted); |
1358 |
} |
1564 |
} |
1359 |
|
1565 |
|
1360 |
|
1566 |
|
|
|
1567 |
#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) |
1361 |
STATIC int |
1568 |
STATIC int |
1362 |
pmatch(pattern, string, squoted) |
1569 |
pmatch(pattern, string) |
1363 |
char *pattern; |
1570 |
const char *pattern; |
1364 |
char *string; |
1571 |
const char *string; |
1365 |
int squoted; |
|
|
1366 |
{ |
1572 |
{ |
1367 |
char *p, *q; |
1573 |
const char *p, *q; |
1368 |
char c; |
1574 |
char c; |
1369 |
|
1575 |
|
1370 |
p = pattern; |
1576 |
p = pattern; |
Lines 1373-1418
Link Here
|
1373 |
switch (c = *p++) { |
1579 |
switch (c = *p++) { |
1374 |
case '\0': |
1580 |
case '\0': |
1375 |
goto breakloop; |
1581 |
goto breakloop; |
1376 |
case CTLESC: |
1582 |
case '\\': |
1377 |
if (squoted && *q == CTLESC) |
1583 |
if (*p) { |
1378 |
q++; |
1584 |
c = *p++; |
1379 |
if (*q++ != *p++) |
1585 |
} |
1380 |
return 0; |
1586 |
goto dft; |
1381 |
break; |
|
|
1382 |
case CTLQUOTEMARK: |
1383 |
continue; |
1384 |
case '?': |
1587 |
case '?': |
1385 |
if (squoted && *q == CTLESC) |
|
|
1386 |
q++; |
1387 |
if (*q++ == '\0') |
1588 |
if (*q++ == '\0') |
1388 |
return 0; |
1589 |
return 0; |
1389 |
break; |
1590 |
break; |
1390 |
case '*': |
1591 |
case '*': |
1391 |
c = *p; |
1592 |
c = *p; |
1392 |
while (c == CTLQUOTEMARK || c == '*') |
1593 |
while (c == '*') |
1393 |
c = *++p; |
1594 |
c = *++p; |
1394 |
if (c != CTLESC && c != CTLQUOTEMARK && |
1595 |
if (c != '\\' && c != '?' && c != '*' && c != '[') { |
1395 |
c != '?' && c != '*' && c != '[') { |
|
|
1396 |
while (*q != c) { |
1596 |
while (*q != c) { |
1397 |
if (squoted && *q == CTLESC && |
|
|
1398 |
q[1] == c) |
1399 |
break; |
1400 |
if (*q == '\0') |
1597 |
if (*q == '\0') |
1401 |
return 0; |
1598 |
return 0; |
1402 |
if (squoted && *q == CTLESC) |
|
|
1403 |
q++; |
1404 |
q++; |
1599 |
q++; |
1405 |
} |
1600 |
} |
1406 |
} |
1601 |
} |
1407 |
do { |
1602 |
do { |
1408 |
if (pmatch(p, q, squoted)) |
1603 |
if (pmatch(p, q)) |
1409 |
return 1; |
1604 |
return 1; |
1410 |
if (squoted && *q == CTLESC) |
|
|
1411 |
q++; |
1412 |
} while (*q++ != '\0'); |
1605 |
} while (*q++ != '\0'); |
1413 |
return 0; |
1606 |
return 0; |
1414 |
case '[': { |
1607 |
case '[': { |
1415 |
char *endp; |
1608 |
const char *endp; |
1416 |
int invert, found; |
1609 |
int invert, found; |
1417 |
char chr; |
1610 |
char chr; |
1418 |
|
1611 |
|
Lines 1420-1430
Link Here
|
1420 |
if (*endp == '!') |
1613 |
if (*endp == '!') |
1421 |
endp++; |
1614 |
endp++; |
1422 |
for (;;) { |
1615 |
for (;;) { |
1423 |
while (*endp == CTLQUOTEMARK) |
|
|
1424 |
endp++; |
1425 |
if (*endp == '\0') |
1616 |
if (*endp == '\0') |
1426 |
goto dft; /* no matching ] */ |
1617 |
goto dft; /* no matching ] */ |
1427 |
if (*endp == CTLESC) |
1618 |
if (*endp == '\\') |
1428 |
endp++; |
1619 |
endp++; |
1429 |
if (*++endp == ']') |
1620 |
if (*++endp == ']') |
1430 |
break; |
1621 |
break; |
Lines 1436-1456
Link Here
|
1436 |
} |
1627 |
} |
1437 |
found = 0; |
1628 |
found = 0; |
1438 |
chr = *q++; |
1629 |
chr = *q++; |
1439 |
if (squoted && chr == CTLESC) |
|
|
1440 |
chr = *q++; |
1441 |
if (chr == '\0') |
1630 |
if (chr == '\0') |
1442 |
return 0; |
1631 |
return 0; |
1443 |
c = *p++; |
1632 |
c = *p++; |
1444 |
do { |
1633 |
do { |
1445 |
if (c == CTLQUOTEMARK) |
1634 |
if (c == '\\') |
1446 |
continue; |
|
|
1447 |
if (c == CTLESC) |
1448 |
c = *p++; |
1635 |
c = *p++; |
1449 |
if (*p == '-' && p[1] != ']') { |
1636 |
if (*p == '-' && p[1] != ']') { |
1450 |
p++; |
1637 |
p++; |
1451 |
while (*p == CTLQUOTEMARK) |
1638 |
if (*p == '\\') |
1452 |
p++; |
|
|
1453 |
if (*p == CTLESC) |
1454 |
p++; |
1639 |
p++; |
1455 |
if (chr >= c && chr <= *p) |
1640 |
if (chr >= c && chr <= *p) |
1456 |
found = 1; |
1641 |
found = 1; |
Lines 1465-1472
Link Here
|
1465 |
break; |
1650 |
break; |
1466 |
} |
1651 |
} |
1467 |
dft: default: |
1652 |
dft: default: |
1468 |
if (squoted && *q == CTLESC) |
|
|
1469 |
q++; |
1470 |
if (*q++ != c) |
1653 |
if (*q++ != c) |
1471 |
return 0; |
1654 |
return 0; |
1472 |
break; |
1655 |
break; |
Lines 1477-1482
Link Here
|
1477 |
return 0; |
1660 |
return 0; |
1478 |
return 1; |
1661 |
return 1; |
1479 |
} |
1662 |
} |
|
|
1663 |
#endif |
1480 |
|
1664 |
|
1481 |
|
1665 |
|
1482 |
|
1666 |
|
Lines 1484-1511
Link Here
|
1484 |
* Remove any CTLESC characters from a string. |
1668 |
* Remove any CTLESC characters from a string. |
1485 |
*/ |
1669 |
*/ |
1486 |
|
1670 |
|
1487 |
void |
1671 |
char * |
1488 |
rmescapes(str) |
1672 |
_rmescapes(str, flag) |
1489 |
char *str; |
1673 |
char *str; |
|
|
1674 |
int flag; |
1490 |
{ |
1675 |
{ |
1491 |
char *p, *q; |
1676 |
char *p, *q, *r; |
|
|
1677 |
static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; |
1678 |
unsigned inquotes; |
1679 |
int notescaped; |
1680 |
int globbing; |
1492 |
|
1681 |
|
1493 |
p = str; |
1682 |
p = strpbrk(str, qchars); |
1494 |
while (*p != CTLESC && *p != CTLQUOTEMARK) { |
1683 |
if (!p) { |
1495 |
if (*p++ == '\0') |
1684 |
return str; |
1496 |
return; |
|
|
1497 |
} |
1685 |
} |
1498 |
q = p; |
1686 |
q = p; |
|
|
1687 |
r = str; |
1688 |
if (flag & RMESCAPE_ALLOC) { |
1689 |
size_t len = p - str; |
1690 |
size_t fulllen = len + strlen(p) + 1; |
1691 |
|
1692 |
if (flag & RMESCAPE_GROW) { |
1693 |
r = makestrspace(fulllen, expdest); |
1694 |
} else if (flag & RMESCAPE_HEAP) { |
1695 |
r = ckmalloc(fulllen); |
1696 |
} else { |
1697 |
r = stalloc(fulllen); |
1698 |
} |
1699 |
q = r; |
1700 |
if (len > 0) { |
1701 |
#ifdef _GNU_SOURCE |
1702 |
q = mempcpy(q, str, len); |
1703 |
#else |
1704 |
memcpy(q, str, len); |
1705 |
q += len; |
1706 |
#endif |
1707 |
} |
1708 |
} |
1709 |
inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; |
1710 |
globbing = flag & RMESCAPE_GLOB; |
1711 |
notescaped = globbing; |
1499 |
while (*p) { |
1712 |
while (*p) { |
1500 |
if (*p == CTLQUOTEMARK) { |
1713 |
if (*p == CTLQUOTEMARK) { |
|
|
1714 |
inquotes = ~inquotes; |
1501 |
p++; |
1715 |
p++; |
|
|
1716 |
notescaped = globbing; |
1502 |
continue; |
1717 |
continue; |
1503 |
} |
1718 |
} |
1504 |
if (*p == CTLESC) |
1719 |
if (*p == '\\') { |
|
|
1720 |
/* naked back slash */ |
1721 |
notescaped = 0; |
1722 |
goto copy; |
1723 |
} |
1724 |
if (*p == CTLESC) { |
1505 |
p++; |
1725 |
p++; |
|
|
1726 |
if (notescaped && inquotes && *p != '/') { |
1727 |
*q++ = '\\'; |
1728 |
} |
1729 |
} |
1730 |
notescaped = globbing; |
1731 |
copy: |
1506 |
*q++ = *p++; |
1732 |
*q++ = *p++; |
1507 |
} |
1733 |
} |
1508 |
*q = '\0'; |
1734 |
*q = '\0'; |
|
|
1735 |
if (flag & RMESCAPE_GROW) { |
1736 |
expdest = r; |
1737 |
STADJUST(q - r + 1, expdest); |
1738 |
} |
1739 |
return r; |
1509 |
} |
1740 |
} |
1510 |
|
1741 |
|
1511 |
|
1742 |
|
Lines 1521-1536
Link Here
|
1521 |
{ |
1752 |
{ |
1522 |
struct stackmark smark; |
1753 |
struct stackmark smark; |
1523 |
int result; |
1754 |
int result; |
1524 |
char *p; |
|
|
1525 |
|
1755 |
|
1526 |
setstackmark(&smark); |
1756 |
setstackmark(&smark); |
1527 |
argbackq = pattern->narg.backquote; |
1757 |
argbackq = pattern->narg.backquote; |
1528 |
STARTSTACKSTR(expdest); |
1758 |
STARTSTACKSTR(expdest); |
1529 |
ifslastp = NULL; |
1759 |
ifslastp = NULL; |
1530 |
argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); |
1760 |
argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); |
1531 |
STPUTC('\0', expdest); |
1761 |
STACKSTRNUL(expdest); |
1532 |
p = grabstackstr(expdest); |
1762 |
result = patmatch(stackblock(), val); |
1533 |
result = patmatch(p, val, 0); |
|
|
1534 |
popstackmark(&smark); |
1763 |
popstackmark(&smark); |
1535 |
return result; |
1764 |
return result; |
1536 |
} |
1765 |
} |
Lines 1539-1563
Link Here
|
1539 |
* Our own itoa(). |
1768 |
* Our own itoa(). |
1540 |
*/ |
1769 |
*/ |
1541 |
|
1770 |
|
1542 |
STATIC char * |
1771 |
STATIC int |
1543 |
cvtnum(num, buf) |
1772 |
cvtnum(long num) { |
1544 |
int num; |
1773 |
int len; |
1545 |
char *buf; |
|
|
1546 |
{ |
1547 |
char temp[32]; |
1548 |
int neg = num < 0; |
1549 |
char *p = temp + 31; |
1550 |
|
1551 |
temp[31] = '\0'; |
1552 |
|
1774 |
|
1553 |
do { |
1775 |
expdest = makestrspace(32, expdest); |
1554 |
*--p = num % 10 + '0'; |
1776 |
len = fmtstr(expdest, 32, "%ld", num); |
1555 |
} while ((num /= 10) != 0); |
1777 |
STADJUST(len, expdest); |
|
|
1778 |
return len; |
1779 |
} |
1556 |
|
1780 |
|
1557 |
if (neg) |
1781 |
static void |
1558 |
*--p = '-'; |
1782 |
varunset(const char *end, const char *var, const char *umsg, int varflags) |
|
|
1783 |
{ |
1784 |
const char *msg; |
1785 |
const char *tail; |
1559 |
|
1786 |
|
1560 |
while (*p) |
1787 |
tail = nullstr; |
1561 |
STPUTC(*p++, buf); |
1788 |
msg = "parameter not set"; |
1562 |
return buf; |
1789 |
if (umsg) { |
|
|
1790 |
if (*end == CTLENDVAR) { |
1791 |
if (varflags & VSNUL) |
1792 |
tail = " or null"; |
1793 |
} else |
1794 |
msg = umsg; |
1795 |
} |
1796 |
error("%.*s: %s%s", end - var - 1, var, msg, tail); |
1563 |
} |
1797 |
} |