OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [misc/] [wordexp/] [wordexp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* vi: set sw=4 ts=4: */
2
/* POSIX.2 wordexp implementation.
3
   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
4
   This file is part of the GNU C Library.
5
   Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
6
 
7
   The GNU C Library is free software; you can redistribute it and/or
8
   modify it under the terms of the GNU Library General Public License as
9
   published by the Free Software Foundation; either version 2 of the
10
   License, or (at your option) any later version.
11
 
12
   The GNU C Library is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
   Library General Public License for more details.
16
 
17
   You should have received a copy of the GNU Library General Public
18
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
19
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
   Boston, MA 02111-1307, USA.  */
21
 
22
#define _GNU_SOURCE
23
#include <sys/cdefs.h>
24
#include <sys/types.h>
25
#include <sys/wait.h>
26
#include <fcntl.h>
27
#include <paths.h>
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
#include <pwd.h>
33
#include <errno.h>
34
#include <assert.h>
35
#include <fnmatch.h>
36
#include <glob.h>
37
#include <wordexp.h>
38
 
39
#define __WORDEXP_FULL
40
//#undef __WORDEXP_FULL
41
 
42
/*
43
 * This is a recursive-descent-style word expansion routine.
44
 */
45
 
46
/* These variables are defined and initialized in the startup code.  */
47
//extern int __libc_argc;
48
//extern char **__libc_argv;
49
 
50
/* FIXME!!!! */
51
int __libc_argc;
52
char **__libc_argv;
53
 
54
/* Some forward declarations */
55
static int parse_dollars(char **word, size_t * word_length,
56
                                                 size_t * max_length, const char *words,
57
                                                 size_t * offset, int flags, wordexp_t * pwordexp,
58
                                                 const char *ifs, const char *ifs_white,
59
                                                 int quoted);
60
static int parse_backtick(char **word, size_t * word_length,
61
                                                  size_t * max_length, const char *words,
62
                                                  size_t * offset, int flags, wordexp_t * pwordexp,
63
                                                  const char *ifs, const char *ifs_white);
64
static int parse_dquote(char **word, size_t * word_length,
65
                                                size_t * max_length, const char *words,
66
                                                size_t * offset, int flags, wordexp_t * pwordexp,
67
                                                const char *ifs, const char *ifs_white);
68
 
69
 
70
 
71
/* The w_*() functions manipulate word lists. */
72
#define W_CHUNK (100)
73
 
74
/* Result of w_newword will be ignored if it's the last word. */
75
static inline char *w_newword(size_t * actlen, size_t * maxlen)
76
{
77
        *actlen = *maxlen = 0;
78
        return NULL;
79
}
80
 
81
/* Add a character to the buffer, allocating room for it if needed.  */
82
static inline char *w_addchar(char *buffer, size_t * actlen,
83
                                                          size_t * maxlen, char ch)
84
         /* (lengths exclude trailing zero) */
85
{
86
 
87
        if (*actlen == *maxlen) {
88
                char *old_buffer = buffer;
89
                assert(buffer == NULL || *maxlen != 0);
90
                *maxlen += W_CHUNK;
91
                buffer = realloc(buffer, 1 + *maxlen);
92
                if (buffer == NULL)
93
                        free(old_buffer);
94
        }
95
 
96
        if (buffer != NULL) {
97
                buffer[*actlen] = ch;
98
                buffer[++(*actlen)] = '\0';
99
        }
100
 
101
        return buffer;
102
}
103
 
104
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
105
static char *w_addmem(char *buffer, size_t * actlen, size_t * maxlen,
106
                                          const char *str, size_t len)
107
{
108
        /* Add a string to the buffer, allocating room for it if needed.
109
         */
110
        if (*actlen + len > *maxlen) {
111
                char *old_buffer = buffer;
112
                assert(buffer == NULL || *maxlen != 0);
113
                *maxlen += MAX(2 * len, W_CHUNK);
114
                buffer = realloc(old_buffer, 1 + *maxlen);
115
                if (buffer == NULL)
116
                        free(old_buffer);
117
        }
118
 
119
        if (buffer != NULL) {
120
                *((char *) mempcpy(&buffer[*actlen], str, len)) = '\0';
121
                *actlen += len;
122
        }
123
        return buffer;
124
}
125
 
126
/* Add a string to the buffer, allocating room for it if needed.  */
127
static char *w_addstr(char *buffer, size_t * actlen, size_t * maxlen,
128
                                          const char *str)
129
         /* (lengths exclude trailing zero) */
130
{
131
        size_t len;
132
        assert(str != NULL);            /* w_addstr only called from this file */
133
        len = strlen(str);
134
 
135
        return w_addmem(buffer, actlen, maxlen, str, len);
136
}
137
 
138
/* Add a word to the wordlist */
139
static int w_addword(wordexp_t * pwordexp, char *word)
140
{
141
        size_t num_p;
142
        char **new_wordv;
143
 
144
        /* Internally, NULL acts like "".  Convert NULLs to "" before
145
         * the caller sees them.
146
         */
147
        if (word == NULL) {
148
                word = strdup("");
149
                if (word == NULL)
150
                        goto no_space;
151
        }
152
 
153
        num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
154
        new_wordv = realloc(pwordexp->we_wordv, sizeof(char *) * num_p);
155
        if (new_wordv != NULL) {
156
                pwordexp->we_wordv = new_wordv;
157
                pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
158
                pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
159
                return 0;
160
        }
161
 
162
  no_space:
163
        return WRDE_NOSPACE;
164
}
165
 
166
/* The parse_*() functions should leave *offset being the offset in 'words'
167
 * to the last character processed.
168
 */
169
static int
170
parse_backslash(char **word, size_t * word_length, size_t * max_length,
171
                                const char *words, size_t * offset)
172
{
173
        /* We are poised _at_ a backslash, not in quotes */
174
 
175
        switch (words[1 + *offset]) {
176
        case 0:
177
                /* Backslash is last character of input words */
178
                return WRDE_SYNTAX;
179
 
180
        case '\n':
181
                ++(*offset);
182
                break;
183
 
184
        default:
185
                *word = w_addchar(*word, word_length, max_length, words[1 + *offset]);
186
                if (*word == NULL)
187
                        return WRDE_NOSPACE;
188
 
189
                ++(*offset);
190
                break;
191
        }
192
 
193
        return 0;
194
}
195
 
196
static int
197
parse_qtd_backslash(char **word, size_t * word_length, size_t * max_length,
198
                                        const char *words, size_t * offset)
199
{
200
        /* We are poised _at_ a backslash, inside quotes */
201
 
202
        switch (words[1 + *offset]) {
203
        case 0:
204
                /* Backslash is last character of input words */
205
                return WRDE_SYNTAX;
206
 
207
        case '\n':
208
                ++(*offset);
209
                break;
210
 
211
        case '$':
212
        case '`':
213
        case '"':
214
        case '\\':
215
                *word =
216
                        w_addchar(*word, word_length, max_length, words[1 + *offset]);
217
                if (*word == NULL)
218
                        return WRDE_NOSPACE;
219
 
220
                ++(*offset);
221
                break;
222
 
223
        default:
224
                *word = w_addchar(*word, word_length, max_length, words[*offset]);
225
                if (*word != NULL)
226
                        *word =
227
                                w_addchar(*word, word_length, max_length,
228
                                                  words[1 + *offset]);
229
 
230
                if (*word == NULL)
231
                        return WRDE_NOSPACE;
232
 
233
                ++(*offset);
234
                break;
235
        }
236
 
237
        return 0;
238
}
239
 
240
static int
241
parse_tilde(char **word, size_t * word_length, size_t * max_length,
242
                        const char *words, size_t * offset, size_t wordc)
243
{
244
        /* We are poised _at_ a tilde */
245
        size_t i;
246
 
247
        if (*word_length != 0) {
248
                if (!((*word)[*word_length - 1] == '=' && wordc == 0)) {
249
                        if (!((*word)[*word_length - 1] == ':'
250
                                  && strchr(*word, '=') && wordc == 0)) {
251
                                *word = w_addchar(*word, word_length, max_length, '~');
252
                                return *word ? 0 : WRDE_NOSPACE;
253
                        }
254
                }
255
        }
256
 
257
        for (i = 1 + *offset; words[i]; i++) {
258
                if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
259
                        words[i] == '\t' || words[i] == 0)
260
                        break;
261
 
262
                if (words[i] == '\\') {
263
                        *word = w_addchar(*word, word_length, max_length, '~');
264
                        return *word ? 0 : WRDE_NOSPACE;
265
                }
266
        }
267
 
268
        if (i == 1 + *offset) {
269
                /* Tilde appears on its own */
270
                uid_t uid;
271
                struct passwd pwd, *tpwd;
272
                int buflen = 1000;
273
                char *home;
274
                char *buffer;
275
                int result;
276
 
277
                /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
278
                   results are unspecified.  We do a lookup on the uid if
279
                   HOME is unset. */
280
 
281
                home = getenv("HOME");
282
                if (home != NULL) {
283
                        *word = w_addstr(*word, word_length, max_length, home);
284
                        if (*word == NULL)
285
                                return WRDE_NOSPACE;
286
                } else {
287
                        uid = getuid();
288
                        buffer = alloca(buflen);
289
 
290
                        while ((result = getpwuid_r(uid, &pwd, buffer, buflen, &tpwd))
291
                                        != 0 && errno == ERANGE)
292
                        {
293
                                buflen += 1000;
294
                                buffer = alloca(buflen);
295
                        }
296
 
297
                        if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL) {
298
                                *word = w_addstr(*word, word_length, max_length, pwd.pw_dir);
299
                                if (*word == NULL)
300
                                        return WRDE_NOSPACE;
301
                        } else {
302
                                *word = w_addchar(*word, word_length, max_length, '~');
303
                                if (*word == NULL)
304
                                        return WRDE_NOSPACE;
305
                        }
306
                }
307
        } else {
308
                /* Look up user name in database to get home directory */
309
                char *user = strndup(&words[1 + *offset], i - (1 + *offset));
310
                struct passwd pwd, *tpwd;
311
                int buflen = 1000;
312
                char *buffer = alloca(buflen);
313
                int result;
314
 
315
                while ((result = getpwnam_r(user, &pwd, buffer, buflen, &tpwd)) != 0
316
                           && errno == ERANGE) {
317
                        buflen += 1000;
318
                        buffer = alloca(buflen);
319
                }
320
 
321
                if (result == 0 && tpwd != NULL && pwd.pw_dir)
322
                        *word = w_addstr(*word, word_length, max_length, pwd.pw_dir);
323
                else {
324
                        /* (invalid login name) */
325
                        *word = w_addchar(*word, word_length, max_length, '~');
326
                        if (*word != NULL)
327
                                *word = w_addstr(*word, word_length, max_length, user);
328
                }
329
 
330
                *offset = i - 1;
331
        }
332
        return *word ? 0 : WRDE_NOSPACE;
333
}
334
 
335
 
336
static int
337
do_parse_glob(const char *glob_word, char **word, size_t * word_length,
338
                          size_t * max_length, wordexp_t * pwordexp, const char *ifs,
339
                          const char *ifs_white)
340
{
341
        int error;
342
        int match;
343
        glob_t globbuf;
344
 
345
        error = glob(glob_word, GLOB_NOCHECK, NULL, &globbuf);
346
 
347
        if (error != 0) {
348
                /* We can only run into memory problems.  */
349
                assert(error == GLOB_NOSPACE);
350
                return WRDE_NOSPACE;
351
        }
352
 
353
        if (ifs && !*ifs) {
354
                /* No field splitting allowed. */
355
                assert(globbuf.gl_pathv[0] != NULL);
356
                *word = w_addstr(*word, word_length, max_length, globbuf.gl_pathv[0]);
357
                for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match) {
358
                        *word = w_addchar(*word, word_length, max_length, ' ');
359
                        if (*word != NULL)
360
                                *word = w_addstr(*word, word_length, max_length,
361
                                                                 globbuf.gl_pathv[match]);
362
                }
363
 
364
                globfree(&globbuf);
365
                return *word ? 0 : WRDE_NOSPACE;
366
        }
367
 
368
        assert(ifs == NULL || *ifs != '\0');
369
        if (*word != NULL) {
370
                free(*word);
371
                *word = w_newword(word_length, max_length);
372
        }
373
 
374
        for (match = 0; match < globbuf.gl_pathc; ++match) {
375
                char *matching_word = strdup(globbuf.gl_pathv[match]);
376
 
377
                if (matching_word == NULL || w_addword(pwordexp, matching_word)) {
378
                        globfree(&globbuf);
379
                        return WRDE_NOSPACE;
380
                }
381
        }
382
 
383
        globfree(&globbuf);
384
        return 0;
385
}
386
 
387
static int
388
parse_glob(char **word, size_t * word_length, size_t * max_length,
389
                   const char *words, size_t * offset, int flags,
390
                   wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
391
{
392
        /* We are poised just after a '*', a '[' or a '?'. */
393
        int error = WRDE_NOSPACE;
394
        int quoted = 0;                          /* 1 if singly-quoted, 2 if doubly */
395
        int i;
396
        wordexp_t glob_list;            /* List of words to glob */
397
 
398
        glob_list.we_wordc = 0;
399
        glob_list.we_wordv = NULL;
400
        glob_list.we_offs = 0;
401
        for (; words[*offset] != '\0'; ++*offset) {
402
                if ((ifs && strchr(ifs, words[*offset])) ||
403
                        (!ifs && strchr(" \t\n", words[*offset])))
404
                        /* Reached IFS */
405
                        break;
406
 
407
                /* Sort out quoting */
408
                if (words[*offset] == '\'') {
409
                        if (quoted == 0) {
410
                                quoted = 1;
411
                                continue;
412
                        } else if (quoted == 1) {
413
                                quoted = 0;
414
                                continue;
415
                        }
416
                } else if (words[*offset] == '"') {
417
                        if (quoted == 0) {
418
                                quoted = 2;
419
                                continue;
420
                        } else if (quoted == 2) {
421
                                quoted = 0;
422
                                continue;
423
                        }
424
                }
425
 
426
                /* Sort out other special characters */
427
                if (quoted != 1 && words[*offset] == '$') {
428
                        error = parse_dollars(word, word_length, max_length, words,
429
                                                                  offset, flags, &glob_list, ifs,
430
                                                                  ifs_white, quoted == 2);
431
                        if (error)
432
                                goto tidy_up;
433
 
434
                        continue;
435
                } else if (words[*offset] == '\\') {
436
                        if (quoted)
437
                                error = parse_qtd_backslash(word, word_length, max_length,
438
                                                                                        words, offset);
439
                        else
440
                                error = parse_backslash(word, word_length, max_length,
441
                                                                                words, offset);
442
 
443
                        if (error)
444
                                goto tidy_up;
445
 
446
                        continue;
447
                }
448
 
449
                *word = w_addchar(*word, word_length, max_length, words[*offset]);
450
                if (*word == NULL)
451
                        goto tidy_up;
452
        }
453
 
454
        /* Don't forget to re-parse the character we stopped at. */
455
        --*offset;
456
 
457
        /* Glob the words */
458
        error = w_addword(&glob_list, *word);
459
        *word = w_newword(word_length, max_length);
460
        for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
461
                error = do_parse_glob(glob_list.we_wordv[i], word, word_length,
462
                                                          max_length, pwordexp, ifs, ifs_white);
463
 
464
        /* Now tidy up */
465
  tidy_up:
466
        wordfree(&glob_list);
467
        return error;
468
}
469
 
470
static int
471
parse_squote(char **word, size_t * word_length, size_t * max_length,
472
                         const char *words, size_t * offset)
473
{
474
        /* We are poised just after a single quote */
475
        for (; words[*offset]; ++(*offset)) {
476
                if (words[*offset] != '\'') {
477
                        *word = w_addchar(*word, word_length, max_length, words[*offset]);
478
                        if (*word == NULL)
479
                                return WRDE_NOSPACE;
480
                } else
481
                        return 0;
482
        }
483
 
484
        /* Unterminated string */
485
        return WRDE_SYNTAX;
486
}
487
 
488
#ifdef __WORDEXP_FULL
489
static int eval_expr(char *expr, long int *result);
490
 
491
static char *_itoa(unsigned long long int value, char *buflim)
492
{
493
        sprintf(buflim, "%llu", value);
494
        return buflim;
495
}
496
 
497
/* Functions to evaluate an arithmetic expression */
498
static int eval_expr_val(char **expr, long int *result)
499
{
500
        int sgn = +1;
501
        char *digit;
502
 
503
        /* Skip white space */
504
        for (digit = *expr; digit && *digit && isspace(*digit); ++digit);
505
 
506
        switch (*digit) {
507
        case '(':
508
 
509
                /* Scan for closing paren */
510
                for (++digit; **expr && **expr != ')'; ++(*expr));
511
 
512
                /* Is there one? */
513
                if (!**expr)
514
                        return WRDE_SYNTAX;
515
 
516
                *(*expr)++ = 0;
517
 
518
                if (eval_expr(digit, result))
519
                        return WRDE_SYNTAX;
520
 
521
                return 0;
522
 
523
        case '+':                                       /* Positive value */
524
                ++digit;
525
                break;
526
 
527
        case '-':                                       /* Negative value */
528
                ++digit;
529
                sgn = -1;
530
                break;
531
 
532
        default:
533
                if (!isdigit(*digit))
534
                        return WRDE_SYNTAX;
535
        }
536
 
537
        *result = 0;
538
        for (; *digit && isdigit(*digit); ++digit)
539
                *result = (*result * 10) + (*digit - '0');
540
 
541
        *expr = digit;
542
        *result *= sgn;
543
        return 0;
544
}
545
 
546
static int eval_expr_multdiv(char **expr, long int *result)
547
{
548
        long int arg;
549
 
550
        /* Read a Value */
551
        if (eval_expr_val(expr, result) != 0)
552
                return WRDE_SYNTAX;
553
 
554
        while (**expr) {
555
                /* Skip white space */
556
                for (; *expr && **expr && isspace(**expr); ++(*expr));
557
 
558
                if (**expr == '*') {
559
                        ++(*expr);
560
                        if (eval_expr_val(expr, &arg) != 0)
561
                                return WRDE_SYNTAX;
562
 
563
                        *result *= arg;
564
                } else if (**expr == '/') {
565
                        ++(*expr);
566
                        if (eval_expr_val(expr, &arg) != 0)
567
                                return WRDE_SYNTAX;
568
 
569
                        *result /= arg;
570
                } else
571
                        break;
572
        }
573
 
574
        return 0;
575
}
576
 
577
static int eval_expr(char *expr, long int *result)
578
{
579
        long int arg;
580
 
581
        /* Read a Multdiv */
582
        if (eval_expr_multdiv(&expr, result) != 0)
583
                return WRDE_SYNTAX;
584
 
585
        while (*expr) {
586
                /* Skip white space */
587
                for (; expr && *expr && isspace(*expr); ++expr);
588
 
589
                if (*expr == '+') {
590
                        ++expr;
591
                        if (eval_expr_multdiv(&expr, &arg) != 0)
592
                                return WRDE_SYNTAX;
593
 
594
                        *result += arg;
595
                } else if (*expr == '-') {
596
                        ++expr;
597
                        if (eval_expr_multdiv(&expr, &arg) != 0)
598
                                return WRDE_SYNTAX;
599
 
600
                        *result -= arg;
601
                } else
602
                        break;
603
        }
604
 
605
        return 0;
606
}
607
 
608
static int
609
parse_arith(char **word, size_t * word_length, size_t * max_length,
610
                        const char *words, size_t * offset, int flags, int bracket)
611
{
612
        /* We are poised just after "$((" or "$[" */
613
        int error;
614
        int paren_depth = 1;
615
        size_t expr_length;
616
        size_t expr_maxlen;
617
        char *expr;
618
 
619
        expr = w_newword(&expr_length, &expr_maxlen);
620
        for (; words[*offset]; ++(*offset)) {
621
                switch (words[*offset]) {
622
                case '$':
623
                        error = parse_dollars(&expr, &expr_length, &expr_maxlen,
624
                                                                  words, offset, flags, NULL, NULL, NULL,
625
                                                                  1);
626
                        /* The ``1'' here is to tell parse_dollars not to
627
                         * split the fields.
628
                         */
629
                        if (error) {
630
                                free(expr);
631
                                return error;
632
                        }
633
                        break;
634
 
635
                case '`':
636
                        (*offset)++;
637
                        error = parse_backtick(&expr, &expr_length, &expr_maxlen,
638
                                                                   words, offset, flags, NULL, NULL, NULL);
639
                        /* The first NULL here is to tell parse_backtick not to
640
                         * split the fields.
641
                         */
642
                        if (error) {
643
                                free(expr);
644
                                return error;
645
                        }
646
                        break;
647
 
648
                case '\\':
649
                        error = parse_qtd_backslash(&expr, &expr_length, &expr_maxlen,
650
                                                                                words, offset);
651
                        if (error) {
652
                                free(expr);
653
                                return error;
654
                        }
655
                        /* I think that a backslash within an
656
                         * arithmetic expansion is bound to
657
                         * cause an error sooner or later anyway though.
658
                         */
659
                        break;
660
 
661
                case ')':
662
                        if (--paren_depth == 0) {
663
                                char result[21];        /* 21 = ceil(log10(2^64)) + 1 */
664
                                long int numresult = 0;
665
                                long long int convertme;
666
 
667
                                if (bracket || words[1 + *offset] != ')') {
668
                                        free(expr);
669
                                        return WRDE_SYNTAX;
670
                                }
671
 
672
                                ++(*offset);
673
 
674
                                /* Go - evaluate. */
675
                                if (*expr && eval_expr(expr, &numresult) != 0) {
676
                                        free(expr);
677
                                        return WRDE_SYNTAX;
678
                                }
679
 
680
                                if (numresult < 0) {
681
                                        convertme = -numresult;
682
                                        *word = w_addchar(*word, word_length, max_length, '-');
683
                                        if (!*word) {
684
                                                free(expr);
685
                                                return WRDE_NOSPACE;
686
                                        }
687
                                } else
688
                                        convertme = numresult;
689
 
690
                                result[20] = '\0';
691
                                *word = w_addstr(*word, word_length, max_length,
692
                                                                 _itoa(convertme, &result[20]));
693
                                free(expr);
694
                                return *word ? 0 : WRDE_NOSPACE;
695
                        }
696
                        expr =
697
                                w_addchar(expr, &expr_length, &expr_maxlen,
698
                                                  words[*offset]);
699
                        if (expr == NULL)
700
                                return WRDE_NOSPACE;
701
 
702
                        break;
703
 
704
                case ']':
705
                        if (bracket && paren_depth == 1) {
706
                                char result[21];        /* 21 = ceil(log10(2^64)) + 1 */
707
                                long int numresult = 0;
708
 
709
                                /* Go - evaluate. */
710
                                if (*expr && eval_expr(expr, &numresult) != 0) {
711
                                        free(expr);
712
                                        return WRDE_SYNTAX;
713
                                }
714
 
715
                                result[20] = '\0';
716
                                *word = w_addstr(*word, word_length, max_length,
717
                                                                 _itoa(numresult, &result[20]));
718
                                free(expr);
719
                                return *word ? 0 : WRDE_NOSPACE;
720
                        }
721
 
722
                        free(expr);
723
                        return WRDE_SYNTAX;
724
 
725
                case '\n':
726
                case ';':
727
                case '{':
728
                case '}':
729
                        free(expr);
730
                        return WRDE_BADCHAR;
731
 
732
                case '(':
733
                        ++paren_depth;
734
                default:
735
                        expr =
736
                                w_addchar(expr, &expr_length, &expr_maxlen,
737
                                                  words[*offset]);
738
                        if (expr == NULL)
739
                                return WRDE_NOSPACE;
740
                }
741
        }
742
 
743
        /* Premature end */
744
        free(expr);
745
        return WRDE_SYNTAX;
746
}
747
 
748
/* Function called by child process in exec_comm() */
749
static void
750
exec_comm_child(char *comm, int *fildes, int showerr, int noexec)
751
{
752
        const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
753
 
754
        /* Execute the command, or just check syntax? */
755
        if (noexec)
756
                args[1] = "-nc";
757
 
758
        /* Redirect output.  */
759
        dup2(fildes[1], 1);
760
        close(fildes[1]);
761
 
762
        /* Redirect stderr to /dev/null if we have to.  */
763
        if (showerr == 0) {
764
                int fd;
765
 
766
                close(2);
767
                fd = open(_PATH_DEVNULL, O_WRONLY);
768
                if (fd >= 0 && fd != 2) {
769
                        dup2(fd, 2);
770
                        close(fd);
771
                }
772
        }
773
 
774
        /* Make sure the subshell doesn't field-split on our behalf. */
775
        unsetenv("IFS");
776
 
777
        close(fildes[0]);
778
        execve(_PATH_BSHELL, (char *const *) args, __environ);
779
 
780
        /* Bad.  What now?  */
781
        abort();
782
}
783
 
784
/* Function to execute a command and retrieve the results */
785
/* pwordexp contains NULL if field-splitting is forbidden */
786
static int
787
exec_comm(char *comm, char **word, size_t * word_length,
788
                  size_t * max_length, int flags, wordexp_t * pwordexp,
789
                  const char *ifs, const char *ifs_white)
790
{
791
        int fildes[2];
792
        int bufsize = 128;
793
        int buflen;
794
        int i;
795
        int status = 0;
796
        size_t maxnewlines = 0;
797
        char *buffer;
798
        pid_t pid;
799
 
800
        /* Don't fork() unless necessary */
801
        if (!comm || !*comm)
802
                return 0;
803
 
804
        if (pipe(fildes))
805
                /* Bad */
806
                return WRDE_NOSPACE;
807
 
808
        if ((pid = fork()) < 0) {
809
                /* Bad */
810
                close(fildes[0]);
811
                close(fildes[1]);
812
                return WRDE_NOSPACE;
813
        }
814
 
815
        if (pid == 0)
816
                exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0);
817
 
818
        /* Parent */
819
 
820
        close(fildes[1]);
821
        buffer = alloca(bufsize);
822
 
823
        if (!pwordexp)
824
                /* Quoted - no field splitting */
825
        {
826
                while (1) {
827
                        if ((buflen = read(fildes[0], buffer, bufsize)) < 1) {
828
                                if (waitpid(pid, &status, WNOHANG) == 0)
829
                                        continue;
830
                                if ((buflen = read(fildes[0], buffer, bufsize)) < 1)
831
                                        break;
832
                        }
833
 
834
                        maxnewlines += buflen;
835
 
836
                        *word = w_addmem(*word, word_length, max_length, buffer, buflen);
837
                        if (*word == NULL)
838
                                goto no_space;
839
                }
840
        } else
841
                /* Not quoted - split fields */
842
        {
843
                int copying = 0;
844
 
845
                /* 'copying' is:
846
                 *  0 when searching for first character in a field not IFS white space
847
                 *  1 when copying the text of a field
848
                 *  2 when searching for possible non-whitespace IFS
849
                 *  3 when searching for non-newline after copying field
850
                 */
851
 
852
                while (1) {
853
                        if ((buflen = read(fildes[0], buffer, bufsize)) < 1) {
854
                                if (waitpid(pid, &status, WNOHANG) == 0)
855
                                        continue;
856
                                if ((buflen = read(fildes[0], buffer, bufsize)) < 1)
857
                                        break;
858
                        }
859
 
860
                        for (i = 0; i < buflen; ++i) {
861
                                if (strchr(ifs, buffer[i]) != NULL) {
862
                                        /* Current character is IFS */
863
                                        if (strchr(ifs_white, buffer[i]) == NULL) {
864
                                                /* Current character is IFS but not whitespace */
865
                                                if (copying == 2) {
866
                                                        /*            current character
867
                                                         *                   |
868
                                                         *                   V
869
                                                         * eg: text<space><comma><space>moretext
870
                                                         *
871
                                                         * So, strip whitespace IFS (like at the start)
872
                                                         */
873
                                                        copying = 0;
874
                                                        continue;
875
                                                }
876
 
877
                                                copying = 0;
878
                                                /* fall through and delimit field.. */
879
                                        } else {
880
                                                if (buffer[i] == '\n') {
881
                                                        /* Current character is (IFS) newline */
882
 
883
                                                        /* If copying a field, this is the end of it,
884
                                                           but maybe all that's left is trailing newlines.
885
                                                           So start searching for a non-newline. */
886
                                                        if (copying == 1)
887
                                                                copying = 3;
888
 
889
                                                        continue;
890
                                                } else {
891
                                                        /* Current character is IFS white space, but
892
                                                           not a newline */
893
 
894
                                                        /* If not either copying a field or searching
895
                                                           for non-newline after a field, ignore it */
896
                                                        if (copying != 1 && copying != 3)
897
                                                                continue;
898
 
899
                                                        /* End of field (search for non-ws IFS afterwards) */
900
                                                        copying = 2;
901
                                                }
902
                                        }
903
 
904
                                        /* First IFS white space (non-newline), or IFS non-whitespace.
905
                                         * Delimit the field.  Nulls are converted by w_addword. */
906
                                        if (w_addword(pwordexp, *word) == WRDE_NOSPACE)
907
                                                goto no_space;
908
 
909
                                        *word = w_newword(word_length, max_length);
910
 
911
                                        maxnewlines = 0;
912
                                        /* fall back round the loop.. */
913
                                } else {
914
                                        /* Not IFS character */
915
 
916
                                        if (copying == 3) {
917
                                                /* Nothing but (IFS) newlines since the last field,
918
                                                   so delimit it here before starting new word */
919
                                                if (w_addword(pwordexp, *word) == WRDE_NOSPACE)
920
                                                        goto no_space;
921
 
922
                                                *word = w_newword(word_length, max_length);
923
                                        }
924
 
925
                                        copying = 1;
926
 
927
                                        if (buffer[i] == '\n')  /* happens if newline not in IFS */
928
                                                maxnewlines++;
929
                                        else
930
                                                maxnewlines = 0;
931
 
932
                                        *word = w_addchar(*word, word_length, max_length,
933
                                                                          buffer[i]);
934
                                        if (*word == NULL)
935
                                                goto no_space;
936
                                }
937
                        }
938
                }
939
        }
940
 
941
        /* Chop off trailing newlines (required by POSIX.2)  */
942
        /* Ensure we don't go back further than the beginning of the
943
           substitution (i.e. remove maxnewlines bytes at most) */
944
        while (maxnewlines-- != 0 &&
945
                   *word_length > 0 && (*word)[*word_length - 1] == '\n') {
946
                (*word)[--*word_length] = '\0';
947
 
948
                /* If the last word was entirely newlines, turn it into a new word
949
                 * which can be ignored if there's nothing following it. */
950
                if (*word_length == 0) {
951
                        free(*word);
952
                        *word = w_newword(word_length, max_length);
953
                        break;
954
                }
955
        }
956
 
957
        close(fildes[0]);
958
 
959
        /* Check for syntax error (re-execute but with "-n" flag) */
960
        if (buflen < 1 && status != 0) {
961
                if ((pid = fork()) < 0) {
962
                        /* Bad */
963
                        return WRDE_NOSPACE;
964
                }
965
 
966
                if (pid == 0) {
967
                        fildes[0] = fildes[1] = -1;
968
                        exec_comm_child(comm, fildes, 0, 1);
969
                }
970
 
971
                if (waitpid(pid, &status, 0) == pid && status != 0)
972
                        return WRDE_SYNTAX;
973
        }
974
 
975
        return 0;
976
 
977
  no_space:
978
        kill(pid, SIGKILL);
979
        waitpid(pid, NULL, 0);
980
        close(fildes[0]);
981
        return WRDE_NOSPACE;
982
}
983
 
984
static int
985
parse_comm(char **word, size_t * word_length, size_t * max_length,
986
                   const char *words, size_t * offset, int flags,
987
                   wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
988
{
989
        /* We are poised just after "$(" */
990
        int paren_depth = 1;
991
        int error = 0;
992
        int quoted = 0;                          /* 1 for singly-quoted, 2 for doubly-quoted */
993
        size_t comm_length;
994
        size_t comm_maxlen;
995
        char *comm = w_newword(&comm_length, &comm_maxlen);
996
 
997
        for (; words[*offset]; ++(*offset)) {
998
                switch (words[*offset]) {
999
                case '\'':
1000
                        if (quoted == 0)
1001
                                quoted = 1;
1002
                        else if (quoted == 1)
1003
                                quoted = 0;
1004
 
1005
                        break;
1006
 
1007
                case '"':
1008
                        if (quoted == 0)
1009
                                quoted = 2;
1010
                        else if (quoted == 2)
1011
                                quoted = 0;
1012
 
1013
                        break;
1014
 
1015
                case ')':
1016
                        if (!quoted && --paren_depth == 0) {
1017
                                /* Go -- give script to the shell */
1018
                                if (comm) {
1019
                                        error = exec_comm(comm, word, word_length, max_length,
1020
                                                                          flags, pwordexp, ifs, ifs_white);
1021
                                        free(comm);
1022
                                }
1023
 
1024
                                return error;
1025
                        }
1026
 
1027
                        /* This is just part of the script */
1028
                        break;
1029
 
1030
                case '(':
1031
                        if (!quoted)
1032
                                ++paren_depth;
1033
                }
1034
 
1035
                comm = w_addchar(comm, &comm_length, &comm_maxlen, words[*offset]);
1036
                if (comm == NULL)
1037
                        return WRDE_NOSPACE;
1038
        }
1039
 
1040
        /* Premature end */
1041
        if (comm)
1042
                free(comm);
1043
 
1044
        return WRDE_SYNTAX;
1045
}
1046
 
1047
static int
1048
parse_backtick(char **word, size_t * word_length, size_t * max_length,
1049
                           const char *words, size_t * offset, int flags,
1050
                           wordexp_t * pwordexp, const char *ifs,
1051
                           const char *ifs_white)
1052
{
1053
        /* We are poised just after "`" */
1054
        int error;
1055
        int squoting = 0;
1056
        size_t comm_length;
1057
        size_t comm_maxlen;
1058
        char *comm = w_newword(&comm_length, &comm_maxlen);
1059
 
1060
        for (; words[*offset]; ++(*offset)) {
1061
                switch (words[*offset]) {
1062
                case '`':
1063
                        /* Go -- give the script to the shell */
1064
                        error = exec_comm(comm, word, word_length, max_length, flags,
1065
                                                          pwordexp, ifs, ifs_white);
1066
                        free(comm);
1067
                        return error;
1068
 
1069
                case '\\':
1070
                        if (squoting) {
1071
                                error = parse_qtd_backslash(&comm, &comm_length, &comm_maxlen,
1072
                                                                                words, offset);
1073
 
1074
                                if (error) {
1075
                                        free(comm);
1076
                                        return error;
1077
                                }
1078
 
1079
                                break;
1080
                        }
1081
 
1082
                        ++(*offset);
1083
                        error = parse_backslash(&comm, &comm_length, &comm_maxlen, words,
1084
                                                                offset);
1085
 
1086
                        if (error) {
1087
                                free(comm);
1088
                                return error;
1089
                        }
1090
 
1091
                        break;
1092
 
1093
                case '\'':
1094
                        squoting = 1 - squoting;
1095
                default:
1096
                        comm = w_addchar(comm, &comm_length, &comm_maxlen,
1097
                                                  words[*offset]);
1098
                        if (comm == NULL)
1099
                                return WRDE_NOSPACE;
1100
                }
1101
        }
1102
 
1103
        /* Premature end */
1104
        free(comm);
1105
        return WRDE_SYNTAX;
1106
}
1107
 
1108
static int
1109
parse_param(char **word, size_t * word_length, size_t * max_length,
1110
                        const char *words, size_t * offset, int flags,
1111
                        wordexp_t * pwordexp, const char *ifs, const char *ifs_white,
1112
                        int quoted)
1113
{
1114
        /* We are poised just after "$" */
1115
        enum action {
1116
                ACT_NONE,
1117
                ACT_RP_SHORT_LEFT = '#',
1118
                ACT_RP_LONG_LEFT = 'L',
1119
                ACT_RP_SHORT_RIGHT = '%',
1120
                ACT_RP_LONG_RIGHT = 'R',
1121
                ACT_NULL_ERROR = '?',
1122
                ACT_NULL_SUBST = '-',
1123
                ACT_NONNULL_SUBST = '+',
1124
                ACT_NULL_ASSIGN = '='
1125
        };
1126
        size_t env_length;
1127
        size_t env_maxlen;
1128
        size_t pat_length;
1129
        size_t pat_maxlen;
1130
        size_t start = *offset;
1131
        char *env;
1132
        char *pattern;
1133
        char *value = NULL;
1134
        enum action action = ACT_NONE;
1135
        int depth = 0;
1136
        int colon_seen = 0;
1137
        int seen_hash = 0;
1138
        int free_value = 0;
1139
        int pattern_is_quoted = 0;       /* 1 for singly-quoted, 2 for doubly-quoted */
1140
        int error;
1141
        int special = 0;
1142
        char buffer[21];
1143
        int brace = words[*offset] == '{';
1144
 
1145
        env = w_newword(&env_length, &env_maxlen);
1146
        pattern = w_newword(&pat_length, &pat_maxlen);
1147
 
1148
        if (brace)
1149
                ++ * offset;
1150
 
1151
        /* First collect the parameter name. */
1152
 
1153
        if (words[*offset] == '#') {
1154
                seen_hash = 1;
1155
                if (!brace)
1156
                        goto envsubst;
1157
                ++*offset;
1158
        }
1159
 
1160
        if (isalpha(words[*offset]) || words[*offset] == '_') {
1161
                /* Normal parameter name. */
1162
                do {
1163
                        env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
1164
                        if (env == NULL)
1165
                                goto no_space;
1166
                }
1167
                while (isalnum(words[++*offset]) || words[*offset] == '_');
1168
        } else if (isdigit(words[*offset])) {
1169
                /* Numeric parameter name. */
1170
                special = 1;
1171
                do {
1172
                        env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
1173
                        if (env == NULL)
1174
                                goto no_space;
1175
                        if (!brace)
1176
                                goto envsubst;
1177
                }
1178
                while (isdigit(words[++*offset]));
1179
        } else if (strchr("*@$", words[*offset]) != NULL) {
1180
                /* Special parameter. */
1181
                special = 1;
1182
                env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
1183
                if (env == NULL)
1184
                        goto no_space;
1185
                ++*offset;
1186
        } else {
1187
                if (brace)
1188
                        goto syntax;
1189
        }
1190
 
1191
        if (brace) {
1192
                /* Check for special action to be applied to the value. */
1193
                switch (words[*offset]) {
1194
                case '}':
1195
                        /* Evaluate. */
1196
                        goto envsubst;
1197
 
1198
                case '#':
1199
                        action = ACT_RP_SHORT_LEFT;
1200
                        if (words[1 + *offset] == '#') {
1201
                                ++*offset;
1202
                                action = ACT_RP_LONG_LEFT;
1203
                        }
1204
                        break;
1205
 
1206
                case '%':
1207
                        action = ACT_RP_SHORT_RIGHT;
1208
                        if (words[1 + *offset] == '%') {
1209
                                ++*offset;
1210
                                action = ACT_RP_LONG_RIGHT;
1211
                        }
1212
                        break;
1213
 
1214
                case ':':
1215
                        if (strchr("-=?+", words[1 + *offset]) == NULL)
1216
                                goto syntax;
1217
 
1218
                        colon_seen = 1;
1219
                        action = words[++*offset];
1220
                        break;
1221
 
1222
                case '-':
1223
                case '=':
1224
                case '?':
1225
                case '+':
1226
                        action = words[*offset];
1227
                        break;
1228
 
1229
                default:
1230
                        goto syntax;
1231
                }
1232
 
1233
                /* Now collect the pattern, but don't expand it yet. */
1234
                ++*offset;
1235
                for (; words[*offset]; ++(*offset)) {
1236
                        switch (words[*offset]) {
1237
                        case '{':
1238
                                if (!pattern_is_quoted)
1239
                                        ++depth;
1240
                                break;
1241
 
1242
                        case '}':
1243
                                if (!pattern_is_quoted) {
1244
                                        if (depth == 0)
1245
                                                goto envsubst;
1246
                                        --depth;
1247
                                }
1248
                                break;
1249
 
1250
                        case '\\':
1251
                                if (pattern_is_quoted)
1252
                                        /* Quoted; treat as normal character. */
1253
                                        break;
1254
 
1255
                                /* Otherwise, it's an escape: next character is literal. */
1256
                                if (words[++*offset] == '\0')
1257
                                        goto syntax;
1258
 
1259
                                pattern = w_addchar(pattern, &pat_length, &pat_maxlen, '\\');
1260
                                if (pattern == NULL)
1261
                                        goto no_space;
1262
 
1263
                                break;
1264
 
1265
                        case '\'':
1266
                                if (pattern_is_quoted == 0)
1267
                                        pattern_is_quoted = 1;
1268
                                else if (pattern_is_quoted == 1)
1269
                                        pattern_is_quoted = 0;
1270
 
1271
                                break;
1272
 
1273
                        case '"':
1274
                                if (pattern_is_quoted == 0)
1275
                                        pattern_is_quoted = 2;
1276
                                else if (pattern_is_quoted == 2)
1277
                                        pattern_is_quoted = 0;
1278
 
1279
                                break;
1280
                        }
1281
 
1282
                        pattern = w_addchar(pattern, &pat_length, &pat_maxlen,
1283
                                                                words[*offset]);
1284
                        if (pattern == NULL)
1285
                                goto no_space;
1286
                }
1287
        }
1288
 
1289
        /* End of input string -- remember to reparse the character that we
1290
         * stopped at.  */
1291
        --(*offset);
1292
 
1293
  envsubst:
1294
        if (words[start] == '{' && words[*offset] != '}')
1295
                goto syntax;
1296
 
1297
        if (env == NULL) {
1298
                if (seen_hash) {
1299
                        /* $# expands to the number of positional parameters */
1300
                        buffer[20] = '\0';
1301
                        value = _itoa(__libc_argc - 1, &buffer[20]);
1302
                        seen_hash = 0;
1303
                } else {
1304
                        /* Just $ on its own */
1305
                        *offset = start - 1;
1306
                        *word = w_addchar(*word, word_length, max_length, '$');
1307
                        return *word ? 0 : WRDE_NOSPACE;
1308
                }
1309
        }
1310
        /* Is it a numeric parameter? */
1311
        else if (isdigit(env[0])) {
1312
                int n = atoi(env);
1313
 
1314
                if (n >= __libc_argc)
1315
                        /* Substitute NULL. */
1316
                        value = NULL;
1317
                else
1318
                        /* Replace with appropriate positional parameter. */
1319
                        value = __libc_argv[n];
1320
        }
1321
        /* Is it a special parameter? */
1322
        else if (special) {
1323
                /* Is it `$$'? */
1324
                if (*env == '$') {
1325
                        buffer[20] = '\0';
1326
                        value = _itoa(getpid(), &buffer[20]);
1327
                }
1328
                /* Is it `${#*}' or `${#@}'? */
1329
                else if ((*env == '*' || *env == '@') && seen_hash) {
1330
                        buffer[20] = '\0';
1331
                        value = _itoa(__libc_argc > 0 ? __libc_argc - 1 : 0,
1332
                                                           &buffer[20]);
1333
                        *word = w_addstr(*word, word_length, max_length, value);
1334
                        free(env);
1335
                        if (pattern)
1336
                                free(pattern);
1337
                        return *word ? 0 : WRDE_NOSPACE;
1338
                }
1339
                /* Is it `$*' or `$@' (unquoted) ? */
1340
                else if (*env == '*' || (*env == '@' && !quoted)) {
1341
                        size_t plist_len = 0;
1342
                        int p;
1343
                        char *end;
1344
 
1345
                        /* Build up value parameter by parameter (copy them) */
1346
                        for (p = 1; __libc_argv[p]; ++p)
1347
                                plist_len += strlen(__libc_argv[p]) + 1;        /* for space */
1348
                        value = malloc(plist_len);
1349
                        if (value == NULL)
1350
                                goto no_space;
1351
                        end = value;
1352
                        *end = 0;
1353
                        for (p = 1; __libc_argv[p]; ++p) {
1354
                                if (p > 1)
1355
                                        *end++ = ' ';
1356
                                end = stpcpy(end, __libc_argv[p]);
1357
                        }
1358
 
1359
                        free_value = 1;
1360
                } else {
1361
                        /* Must be a quoted `$@' */
1362
                        assert(*env == '@' && quoted);
1363
 
1364
                        /* Each parameter is a separate word ("$@") */
1365
                        if (__libc_argc == 2)
1366
                                value = __libc_argv[1];
1367
                        else if (__libc_argc > 2) {
1368
                                int p;
1369
 
1370
                                /* Append first parameter to current word. */
1371
                                value = w_addstr(*word, word_length, max_length,
1372
                                                                 __libc_argv[1]);
1373
                                if (value == NULL || w_addword(pwordexp, value))
1374
                                        goto no_space;
1375
 
1376
                                for (p = 2; __libc_argv[p + 1]; p++) {
1377
                                        char *newword = strdup(__libc_argv[p]);
1378
 
1379
                                        if (newword == NULL || w_addword(pwordexp, newword))
1380
                                                goto no_space;
1381
                                }
1382
 
1383
                                /* Start a new word with the last parameter. */
1384
                                *word = w_newword(word_length, max_length);
1385
                                value = __libc_argv[p];
1386
                        } else {
1387
                                free(env);
1388
                                free(pattern);
1389
                                return 0;
1390
                        }
1391
                }
1392
        } else
1393
                value = getenv(env);
1394
 
1395
        if (value == NULL && (flags & WRDE_UNDEF)) {
1396
                /* Variable not defined. */
1397
                error = WRDE_BADVAL;
1398
                goto do_error;
1399
        }
1400
 
1401
        if (action != ACT_NONE) {
1402
                int expand_pattern = 0;
1403
 
1404
                /* First, find out if we need to expand pattern (i.e. if we will
1405
                 * use it). */
1406
                switch (action) {
1407
                case ACT_RP_SHORT_LEFT:
1408
                case ACT_RP_LONG_LEFT:
1409
                case ACT_RP_SHORT_RIGHT:
1410
                case ACT_RP_LONG_RIGHT:
1411
                        /* Always expand for these. */
1412
                        expand_pattern = 1;
1413
                        break;
1414
 
1415
                case ACT_NULL_ERROR:
1416
                case ACT_NULL_SUBST:
1417
                case ACT_NULL_ASSIGN:
1418
                        if (!value || (!*value && colon_seen))
1419
                                /* If param is unset, or set but null and a colon has been seen,
1420
                                   the expansion of the pattern will be needed. */
1421
                                expand_pattern = 1;
1422
 
1423
                        break;
1424
 
1425
                case ACT_NONNULL_SUBST:
1426
                        /* Expansion of word will be needed if parameter is set and not null,
1427
                           or set null but no colon has been seen. */
1428
                        if (value && (*value || !colon_seen))
1429
                                expand_pattern = 1;
1430
 
1431
                        break;
1432
 
1433
                default:
1434
                        assert(!"Unrecognised action!");
1435
                }
1436
 
1437
                if (expand_pattern) {
1438
                        /* We need to perform tilde expansion, parameter expansion,
1439
                           command substitution, and arithmetic expansion.  We also
1440
                           have to be a bit careful with wildcard characters, as
1441
                           pattern might be given to fnmatch soon.  To do this, we
1442
                           convert quotes to escapes. */
1443
 
1444
                        char *expanded;
1445
                        size_t exp_len;
1446
                        size_t exp_maxl;
1447
                        char *p;
1448
                        int quoted = 0;          /* 1: single quotes; 2: double */
1449
 
1450
                        expanded = w_newword(&exp_len, &exp_maxl);
1451
                        for (p = pattern; p && *p; p++) {
1452
                                size_t offset;
1453
 
1454
                                switch (*p) {
1455
                                case '"':
1456
                                        if (quoted == 2)
1457
                                                quoted = 0;
1458
                                        else if (quoted == 0)
1459
                                                quoted = 2;
1460
                                        else
1461
                                                break;
1462
 
1463
                                        continue;
1464
 
1465
                                case '\'':
1466
                                        if (quoted == 1)
1467
                                                quoted = 0;
1468
                                        else if (quoted == 0)
1469
                                                quoted = 1;
1470
                                        else
1471
                                                break;
1472
 
1473
                                        continue;
1474
 
1475
                                case '*':
1476
                                case '?':
1477
                                        if (quoted) {
1478
                                                /* Convert quoted wildchar to escaped wildchar. */
1479
                                                expanded = w_addchar(expanded, &exp_len,
1480
                                                                                         &exp_maxl, '\\');
1481
 
1482
                                                if (expanded == NULL)
1483
                                                        goto no_space;
1484
                                        }
1485
                                        break;
1486
 
1487
                                case '$':
1488
                                        offset = 0;
1489
                                        error = parse_dollars(&expanded, &exp_len, &exp_maxl, p,
1490
                                                                          &offset, flags, NULL, NULL, NULL, 1);
1491
                                        if (error) {
1492
                                                if (free_value)
1493
                                                        free(value);
1494
 
1495
                                                if (expanded)
1496
                                                        free(expanded);
1497
 
1498
                                                goto do_error;
1499
                                        }
1500
 
1501
                                        p += offset;
1502
                                        continue;
1503
 
1504
                                case '~':
1505
                                        if (quoted || exp_len)
1506
                                                break;
1507
 
1508
                                        offset = 0;
1509
                                        error = parse_tilde(&expanded, &exp_len, &exp_maxl, p,
1510
                                                                                &offset, 0);
1511
                                        if (error) {
1512
                                                if (free_value)
1513
                                                        free(value);
1514
 
1515
                                                if (expanded)
1516
                                                        free(expanded);
1517
 
1518
                                                goto do_error;
1519
                                        }
1520
 
1521
                                        p += offset;
1522
                                        continue;
1523
 
1524
                                case '\\':
1525
                                        expanded = w_addchar(expanded, &exp_len, &exp_maxl, '\\');
1526
                                        ++p;
1527
                                        assert(*p);     /* checked when extracted initially */
1528
                                        if (expanded == NULL)
1529
                                                goto no_space;
1530
                                }
1531
 
1532
                                expanded = w_addchar(expanded, &exp_len, &exp_maxl, *p);
1533
 
1534
                                if (expanded == NULL)
1535
                                        goto no_space;
1536
                        }
1537
 
1538
                        if (pattern)
1539
                                free(pattern);
1540
 
1541
                        pattern = expanded;
1542
                }
1543
 
1544
                switch (action) {
1545
                case ACT_RP_SHORT_LEFT:
1546
                case ACT_RP_LONG_LEFT:
1547
                case ACT_RP_SHORT_RIGHT:
1548
                case ACT_RP_LONG_RIGHT:
1549
                {
1550
                        char *p;
1551
                        char c;
1552
                        char *end;
1553
 
1554
                        if (value == NULL || pattern == NULL || *pattern == '\0')
1555
                                break;
1556
 
1557
                        end = value + strlen(value);
1558
 
1559
                        switch (action) {
1560
                        case ACT_RP_SHORT_LEFT:
1561
                                for (p = value; p <= end; ++p) {
1562
                                        c = *p;
1563
                                        *p = '\0';
1564
                                        if (fnmatch(pattern, value, 0) != FNM_NOMATCH) {
1565
                                                *p = c;
1566
                                                if (free_value) {
1567
                                                        char *newval = strdup(p);
1568
 
1569
                                                        if (newval == NULL) {
1570
                                                                free(value);
1571
                                                                goto no_space;
1572
                                                        }
1573
                                                        free(value);
1574
                                                        value = newval;
1575
                                                } else
1576
                                                        value = p;
1577
                                                break;
1578
                                        }
1579
                                        *p = c;
1580
                                }
1581
 
1582
                                break;
1583
 
1584
                        case ACT_RP_LONG_LEFT:
1585
                                for (p = end; p >= value; --p) {
1586
                                        c = *p;
1587
                                        *p = '\0';
1588
                                        if (fnmatch(pattern, value, 0) != FNM_NOMATCH) {
1589
                                                *p = c;
1590
                                                if (free_value) {
1591
                                                        char *newval = strdup(p);
1592
 
1593
                                                        if (newval == NULL) {
1594
                                                                free(value);
1595
                                                                goto no_space;
1596
                                                        }
1597
                                                        free(value);
1598
                                                        value = newval;
1599
                                                } else
1600
                                                        value = p;
1601
                                                break;
1602
                                        }
1603
                                        *p = c;
1604
                                }
1605
 
1606
                                break;
1607
 
1608
                        case ACT_RP_SHORT_RIGHT:
1609
                                for (p = end; p >= value; --p) {
1610
                                        if (fnmatch(pattern, p, 0) != FNM_NOMATCH) {
1611
                                                char *newval;
1612
 
1613
                                                newval = malloc(p - value + 1);
1614
 
1615
                                                if (newval == NULL) {
1616
                                                        if (free_value)
1617
                                                                free(value);
1618
                                                        goto no_space;
1619
                                                }
1620
 
1621
                                                *(char *) mempcpy(newval, value, p - value) = '\0';
1622
                                                if (free_value)
1623
                                                        free(value);
1624
                                                value = newval;
1625
                                                free_value = 1;
1626
                                                break;
1627
                                        }
1628
                                }
1629
 
1630
                                break;
1631
 
1632
                        case ACT_RP_LONG_RIGHT:
1633
                                for (p = value; p <= end; ++p) {
1634
                                        if (fnmatch(pattern, p, 0) != FNM_NOMATCH) {
1635
                                                char *newval;
1636
 
1637
                                                newval = malloc(p - value + 1);
1638
 
1639
                                                if (newval == NULL) {
1640
                                                        if (free_value)
1641
                                                                free(value);
1642
                                                        goto no_space;
1643
                                                }
1644
 
1645
                                                *(char *) mempcpy(newval, value, p - value) = '\0';
1646
                                                if (free_value)
1647
                                                        free(value);
1648
                                                value = newval;
1649
                                                free_value = 1;
1650
                                                break;
1651
                                        }
1652
                                }
1653
 
1654
                                break;
1655
 
1656
                        default:
1657
                                break;
1658
                        }
1659
 
1660
                        break;
1661
                }
1662
 
1663
                case ACT_NULL_ERROR:
1664
                        if (value && *value)
1665
                                /* Substitute parameter */
1666
                                break;
1667
 
1668
                        error = 0;
1669
                        if (!colon_seen && value)
1670
                                /* Substitute NULL */
1671
                                ;
1672
                        else if (*pattern)
1673
                                fprintf(stderr, "%s: %s\n", env, pattern);
1674
                        else {
1675
                                fprintf(stderr, "%s: parameter null or not set\n", env);
1676
                                error = WRDE_BADVAL;
1677
                        }
1678
 
1679
                        if (free_value)
1680
                                free(value);
1681
                        goto do_error;
1682
 
1683
                case ACT_NULL_SUBST:
1684
                        if (value && *value)
1685
                                /* Substitute parameter */
1686
                                break;
1687
 
1688
                        if (free_value && value)
1689
                                free(value);
1690
 
1691
                        if (!colon_seen && value)
1692
                                /* Substitute NULL */
1693
                                goto success;
1694
 
1695
                        value = pattern ? strdup(pattern) : pattern;
1696
                        free_value = 1;
1697
 
1698
                        if (pattern && !value)
1699
                                goto no_space;
1700
 
1701
                        break;
1702
 
1703
                case ACT_NONNULL_SUBST:
1704
                        if (value && (*value || !colon_seen)) {
1705
                                if (free_value && value)
1706
                                        free(value);
1707
 
1708
                                value = pattern ? strdup(pattern) : pattern;
1709
                                free_value = 1;
1710
 
1711
                                if (pattern && !value)
1712
                                        goto no_space;
1713
 
1714
                                break;
1715
                        }
1716
 
1717
                        /* Substitute NULL */
1718
                        if (free_value)
1719
                                free(value);
1720
                        goto success;
1721
 
1722
                case ACT_NULL_ASSIGN:
1723
                        if (value && *value)
1724
                                /* Substitute parameter */
1725
                                break;
1726
 
1727
                        if (!colon_seen && value) {
1728
                                /* Substitute NULL */
1729
                                if (free_value)
1730
                                        free(value);
1731
                                goto success;
1732
                        }
1733
 
1734
                        if (free_value && value)
1735
                                free(value);
1736
 
1737
                        value = pattern ? strdup(pattern) : pattern;
1738
                        free_value = 1;
1739
 
1740
                        if (pattern && !value)
1741
                                goto no_space;
1742
 
1743
                        setenv(env, value, 1);
1744
                        break;
1745
 
1746
                default:
1747
                        assert(!"Unrecognised action!");
1748
                }
1749
        }
1750
 
1751
        free(env);
1752
        env = NULL;
1753
        free(pattern);
1754
        pattern = NULL;
1755
 
1756
        if (seen_hash) {
1757
                char param_length[21];
1758
 
1759
                param_length[20] = '\0';
1760
                *word = w_addstr(*word, word_length, max_length,
1761
                                                 _itoa(value ? strlen(value) : 0,
1762
                                                                        &param_length[20]));
1763
                if (free_value) {
1764
                        assert(value != NULL);
1765
                        free(value);
1766
                }
1767
 
1768
                return *word ? 0 : WRDE_NOSPACE;
1769
        }
1770
 
1771
        if (value == NULL)
1772
                return 0;
1773
 
1774
        if (quoted || !pwordexp) {
1775
                /* Quoted - no field split */
1776
                *word = w_addstr(*word, word_length, max_length, value);
1777
                if (free_value)
1778
                        free(value);
1779
 
1780
                return *word ? 0 : WRDE_NOSPACE;
1781
        } else {
1782
                /* Need to field-split */
1783
                char *value_copy = strdup(value);       /* Don't modify value */
1784
                char *field_begin = value_copy;
1785
                int seen_nonws_ifs = 0;
1786
 
1787
                if (free_value)
1788
                        free(value);
1789
 
1790
                if (value_copy == NULL)
1791
                        goto no_space;
1792
 
1793
                do {
1794
                        char *field_end = field_begin;
1795
                        char *next_field;
1796
 
1797
                        /* If this isn't the first field, start a new word */
1798
                        if (field_begin != value_copy) {
1799
                                if (w_addword(pwordexp, *word) == WRDE_NOSPACE) {
1800
                                        free(value_copy);
1801
                                        goto no_space;
1802
                                }
1803
 
1804
                                *word = w_newword(word_length, max_length);
1805
                        }
1806
 
1807
                        /* Skip IFS whitespace before the field */
1808
                        field_begin += strspn(field_begin, ifs_white);
1809
 
1810
                        if (!seen_nonws_ifs && *field_begin == 0)
1811
                                /* Nothing but whitespace */
1812
                                break;
1813
 
1814
                        /* Search for the end of the field */
1815
                        field_end = field_begin + strcspn(field_begin, ifs);
1816
 
1817
                        /* Set up pointer to the character after end of field and
1818
                           skip whitespace IFS after it. */
1819
                        next_field = field_end + strspn(field_end, ifs_white);
1820
 
1821
                        /* Skip at most one non-whitespace IFS character after the field */
1822
                        seen_nonws_ifs = 0;
1823
                        if (*next_field && strchr(ifs, *next_field)) {
1824
                                seen_nonws_ifs = 1;
1825
                                next_field++;
1826
                        }
1827
 
1828
                        /* Null-terminate it */
1829
                        *field_end = 0;
1830
 
1831
                        /* Tag a copy onto the current word */
1832
                        *word = w_addstr(*word, word_length, max_length, field_begin);
1833
 
1834
                        if (*word == NULL && *field_begin != '\0') {
1835
                                free(value_copy);
1836
                                goto no_space;
1837
                        }
1838
 
1839
                        field_begin = next_field;
1840
                }
1841
                while (seen_nonws_ifs || *field_begin);
1842
 
1843
                free(value_copy);
1844
        }
1845
 
1846
        return 0;
1847
 
1848
  success:
1849
        error = 0;
1850
        goto do_error;
1851
 
1852
  no_space:
1853
        error = WRDE_NOSPACE;
1854
        goto do_error;
1855
 
1856
  syntax:
1857
        error = WRDE_SYNTAX;
1858
 
1859
  do_error:
1860
        if (env)
1861
                free(env);
1862
 
1863
        if (pattern)
1864
                free(pattern);
1865
 
1866
        return error;
1867
}
1868
#else
1869
static inline int
1870
parse_backtick(char **word, size_t * word_length, size_t * max_length,
1871
                           const char *words, size_t * offset, int flags,
1872
                           wordexp_t * pwordexp, const char *ifs,
1873
                           const char *ifs_white)
1874
{
1875
        return 0;
1876
}
1877
#endif
1878
 
1879
static int
1880
parse_dollars(char **word, size_t * word_length, size_t * max_length,
1881
                          const char *words, size_t * offset, int flags,
1882
                          wordexp_t * pwordexp, const char *ifs, const char *ifs_white,
1883
                          int quoted)
1884
{
1885
        /* We are poised _at_ "$" */
1886
        switch (words[1 + *offset]) {
1887
        case '"':
1888
        case '\'':
1889
        case 0:
1890
                *word = w_addchar(*word, word_length, max_length, '$');
1891
                return *word ? 0 : WRDE_NOSPACE;
1892
 
1893
#ifdef __WORDEXP_FULL
1894
        case '(':
1895
                if (words[2 + *offset] == '(') {
1896
                        /* Differentiate between $((1+3)) and $((echo);(ls)) */
1897
                        int i = 3 + *offset;
1898
                        int depth = 0;
1899
 
1900
                        while (words[i] && !(depth == 0 && words[i] == ')')) {
1901
                                if (words[i] == '(')
1902
                                        ++depth;
1903
                                else if (words[i] == ')')
1904
                                        --depth;
1905
 
1906
                                ++i;
1907
                        }
1908
 
1909
                        if (words[i] == ')' && words[i + 1] == ')') {
1910
                                (*offset) += 3;
1911
                                /* Call parse_arith -- 0 is for "no brackets" */
1912
                                return parse_arith(word, word_length, max_length, words,
1913
                                                                   offset, flags, 0);
1914
                        }
1915
                }
1916
 
1917
                if (flags & WRDE_NOCMD)
1918
                        return WRDE_CMDSUB;
1919
 
1920
                (*offset) += 2;
1921
                return parse_comm(word, word_length, max_length, words, offset,
1922
                                                  flags, quoted ? NULL : pwordexp, ifs, ifs_white);
1923
 
1924
        case '[':
1925
                (*offset) += 2;
1926
                /* Call parse_arith -- 1 is for "brackets" */
1927
                return parse_arith(word, word_length, max_length, words, offset,
1928
                                                   flags, 1);
1929
 
1930
        case '{':
1931
        default:
1932
                ++(*offset);                    /* parse_param needs to know if "{" is there */
1933
                return parse_param(word, word_length, max_length, words, offset,
1934
                                                   flags, pwordexp, ifs, ifs_white, quoted);
1935
#else
1936
        default:
1937
                ++(*offset);                    /* parse_param needs to know if "{" is there */
1938
                return 0;
1939
#endif
1940
        }
1941
}
1942
 
1943
static int
1944
parse_dquote(char **word, size_t * word_length, size_t * max_length,
1945
                         const char *words, size_t * offset, int flags,
1946
                         wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
1947
{
1948
        /* We are poised just after a double-quote */
1949
        int error;
1950
 
1951
        for (; words[*offset]; ++(*offset)) {
1952
                switch (words[*offset]) {
1953
                case '"':
1954
                        return 0;
1955
 
1956
                case '$':
1957
                        error = parse_dollars(word, word_length, max_length, words, offset,
1958
                                                          flags, pwordexp, ifs, ifs_white, 1);
1959
                        /* The ``1'' here is to tell parse_dollars not to
1960
                         * split the fields.  It may need to, however ("$@").
1961
                         */
1962
                        if (error)
1963
                                return error;
1964
 
1965
                        break;
1966
 
1967
                case '`':
1968
                        if (flags & WRDE_NOCMD)
1969
                                return WRDE_CMDSUB;
1970
 
1971
                        ++(*offset);
1972
                        error = parse_backtick(word, word_length, max_length, words,
1973
                                                                   offset, flags, NULL, NULL, NULL);
1974
                        /* The first NULL here is to tell parse_backtick not to
1975
                         * split the fields.
1976
                         */
1977
                        if (error)
1978
                                return error;
1979
 
1980
                        break;
1981
 
1982
                case '\\':
1983
                        error = parse_qtd_backslash(word, word_length, max_length, words,
1984
                                                                        offset);
1985
 
1986
                        if (error)
1987
                                return error;
1988
 
1989
                        break;
1990
 
1991
                default:
1992
                        *word = w_addchar(*word, word_length, max_length, words[*offset]);
1993
                        if (*word == NULL)
1994
                                return WRDE_NOSPACE;
1995
                }
1996
        }
1997
 
1998
        /* Unterminated string */
1999
        return WRDE_SYNTAX;
2000
}
2001
 
2002
/*
2003
 * wordfree() is to be called after pwordexp is finished with.
2004
 */
2005
 
2006
void wordfree(wordexp_t * pwordexp)
2007
{
2008
 
2009
        /* wordexp can set pwordexp to NULL */
2010
        if (pwordexp && pwordexp->we_wordv) {
2011
                char **wordv = pwordexp->we_wordv;
2012
 
2013
                for (wordv += pwordexp->we_offs; *wordv; ++wordv)
2014
                        free(*wordv);
2015
 
2016
                free(pwordexp->we_wordv);
2017
                pwordexp->we_wordv = NULL;
2018
        }
2019
}
2020
 
2021
/*
2022
 * wordexp()
2023
 */
2024
 
2025
int wordexp(const char *words, wordexp_t * we, int flags)
2026
{
2027
        size_t words_offset;
2028
        size_t word_length;
2029
        size_t max_length;
2030
        char *word = w_newword(&word_length, &max_length);
2031
        int error;
2032
        char *ifs;
2033
        char ifs_white[4];
2034
        wordexp_t old_word = *we;
2035
 
2036
        if (flags & WRDE_REUSE) {
2037
                /* Minimal implementation of WRDE_REUSE for now */
2038
                wordfree(we);
2039
                old_word.we_wordv = NULL;
2040
        }
2041
 
2042
        if ((flags & WRDE_APPEND) == 0) {
2043
                we->we_wordc = 0;
2044
 
2045
                if (flags & WRDE_DOOFFS) {
2046
                        we->we_wordv = calloc(1 + we->we_offs, sizeof(char *));
2047
                        if (we->we_wordv == NULL) {
2048
                                error = WRDE_NOSPACE;
2049
                                goto do_error;
2050
                        }
2051
                } else {
2052
                        we->we_wordv = calloc(1, sizeof(char *));
2053
                        if (we->we_wordv == NULL) {
2054
                                error = WRDE_NOSPACE;
2055
                                goto do_error;
2056
                        }
2057
 
2058
                        we->we_offs = 0;
2059
                }
2060
        }
2061
 
2062
        /* Find out what the field separators are.
2063
         * There are two types: whitespace and non-whitespace.
2064
         */
2065
        ifs = getenv("IFS");
2066
 
2067
        if (!ifs)
2068
                /* IFS unset - use <space><tab><newline>. */
2069
                ifs = strcpy(ifs_white, " \t\n");
2070
        else {
2071
                char *ifsch = ifs;
2072
                char *whch = ifs_white;
2073
 
2074
                /* Start off with no whitespace IFS characters */
2075
                ifs_white[0] = '\0';
2076
 
2077
                while (*ifsch != '\0') {
2078
                        if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n')) {
2079
                                /* Whitespace IFS.  See first whether it is already in our
2080
                                   collection.  */
2081
                                char *runp = ifs_white;
2082
 
2083
                                while (runp < whch && *runp != '\0' && *runp != *ifsch)
2084
                                        ++runp;
2085
 
2086
                                if (runp == whch)
2087
                                        *whch++ = *ifsch;
2088
                        }
2089
 
2090
                        ++ifsch;
2091
                }
2092
                *whch = '\0';
2093
        }
2094
 
2095
        for (words_offset = 0; words[words_offset]; ++words_offset)
2096
                switch (words[words_offset]) {
2097
                case '\\':
2098
                        error = parse_backslash(&word, &word_length, &max_length, words,
2099
                                                                &words_offset);
2100
 
2101
                        if (error)
2102
                                goto do_error;
2103
 
2104
                        break;
2105
 
2106
                case '$':
2107
                        error = parse_dollars(&word, &word_length, &max_length, words,
2108
                                                                  &words_offset, flags, we, ifs, ifs_white,
2109
                                                                  0);
2110
 
2111
                        if (error)
2112
                                goto do_error;
2113
 
2114
                        break;
2115
 
2116
                case '`':
2117
                        if (flags & WRDE_NOCMD) {
2118
                                error = WRDE_CMDSUB;
2119
                                goto do_error;
2120
                        }
2121
 
2122
                        ++words_offset;
2123
                        error = parse_backtick(&word, &word_length, &max_length, words,
2124
                                                                   &words_offset, flags, we, ifs,
2125
                                                                   ifs_white);
2126
 
2127
                        if (error)
2128
                                goto do_error;
2129
 
2130
                        break;
2131
 
2132
                case '"':
2133
                        ++words_offset;
2134
                        error = parse_dquote(&word, &word_length, &max_length, words,
2135
                                                                 &words_offset, flags, we, ifs, ifs_white);
2136
 
2137
                        if (error)
2138
                                goto do_error;
2139
 
2140
                        if (!word_length) {
2141
                                error = w_addword(we, NULL);
2142
 
2143
                                if (error)
2144
                                        return error;
2145
                        }
2146
 
2147
                        break;
2148
 
2149
                case '\'':
2150
                        ++words_offset;
2151
                        error = parse_squote(&word, &word_length, &max_length, words,
2152
                                                                 &words_offset);
2153
 
2154
                        if (error)
2155
                                goto do_error;
2156
 
2157
                        if (!word_length) {
2158
                                error = w_addword(we, NULL);
2159
 
2160
                                if (error)
2161
                                        return error;
2162
                        }
2163
 
2164
                        break;
2165
 
2166
                case '~':
2167
                        error = parse_tilde(&word, &word_length, &max_length, words,
2168
                                                                &words_offset, we->we_wordc);
2169
 
2170
                        if (error)
2171
                                goto do_error;
2172
 
2173
                        break;
2174
 
2175
                case '*':
2176
                case '[':
2177
                case '?':
2178
                        error = parse_glob(&word, &word_length, &max_length, words,
2179
                                                           &words_offset, flags, we, ifs, ifs_white);
2180
 
2181
                        if (error)
2182
                                goto do_error;
2183
 
2184
                        break;
2185
 
2186
                default:
2187
                        /* Is it a word separator? */
2188
                        if (strchr(" \t", words[words_offset]) == NULL) {
2189
                                char ch = words[words_offset];
2190
 
2191
                                /* Not a word separator -- but is it a valid word char? */
2192
                                if (strchr("\n|&;<>(){}", ch)) {
2193
                                        /* Fail */
2194
                                        error = WRDE_BADCHAR;
2195
                                        goto do_error;
2196
                                }
2197
 
2198
                                /* "Ordinary" character -- add it to word */
2199
                                word = w_addchar(word, &word_length, &max_length, ch);
2200
                                if (word == NULL) {
2201
                                        error = WRDE_NOSPACE;
2202
                                        goto do_error;
2203
                                }
2204
 
2205
                                break;
2206
                        }
2207
 
2208
                        /* If a word has been delimited, add it to the list. */
2209
                        if (word != NULL) {
2210
                                error = w_addword(we, word);
2211
                                if (error)
2212
                                        goto do_error;
2213
                        }
2214
 
2215
                        word = w_newword(&word_length, &max_length);
2216
                }
2217
 
2218
        /* End of string */
2219
 
2220
        /* There was a word separator at the end */
2221
        if (word == NULL)                       /* i.e. w_newword */
2222
                return 0;
2223
 
2224
        /* There was no field separator at the end */
2225
        return w_addword(we, word);
2226
 
2227
  do_error:
2228
        /* Error:
2229
         *  free memory used (unless error is WRDE_NOSPACE), and
2230
         *  set we members back to what they were.
2231
         */
2232
 
2233
        if (word != NULL)
2234
                free(word);
2235
 
2236
        if (error == WRDE_NOSPACE)
2237
                return WRDE_NOSPACE;
2238
 
2239
        if ((flags & WRDE_APPEND) == 0)
2240
                wordfree(we);
2241
 
2242
        *we = old_word;
2243
        return error;
2244
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.