7c9f06be3955a561af45707410ec349b4522ccaa
[rsync/rsync.git] / popt / poptparse.c
1 /* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
2    file accompanying popt source distributions, available from 
3    ftp://ftp.redhat.com/pub/code/popt */
4
5 #include "system.h"
6
7 #define POPT_ARGV_ARRAY_GROW_DELTA 5
8
9 int poptDupArgv(int argc, const char **argv,
10                 int * argcPtr, const char *** argvPtr)
11 {
12     size_t nb = (argc + 1) * sizeof(*argv);
13     const char ** argv2;
14     char * dst;
15     int i;
16
17     for (i = 0; i < argc; i++) {
18         if (argv[i] == NULL)
19             return POPT_ERROR_NOARG;
20         nb += strlen(argv[i]) + 1;
21     }
22         
23     dst = malloc(nb);
24     argv2 = (void *) dst;
25     dst += (argc + 1) * sizeof(*argv);
26
27     for (i = 0; i < argc; i++) {
28         argv2[i] = dst;
29         dst += strlen(strcpy(dst, argv[i])) + 1;
30     }
31     argv2[argc] = NULL;
32
33     *argvPtr = argv2;
34     *argcPtr = argc;
35     return 0;
36 }
37
38 int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
39 {
40     const char * src;
41     char quote = '\0';
42     int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
43     const char ** argv = malloc(sizeof(*argv) * argvAlloced);
44     int argc = 0;
45     int buflen = strlen(s) + 1;
46     char * buf = memset(alloca(buflen), 0, buflen);
47
48     argv[argc] = buf;
49
50     for (src = s; *src; src++) {
51         if (quote == *src) {
52             quote = '\0';
53         } else if (quote) {
54             if (*src == '\\') {
55                 src++;
56                 if (!*src) {
57                     free(argv);
58                     return POPT_ERROR_BADQUOTE;
59                 }
60                 if (*src != quote) *buf++ = '\\';
61             }
62             *buf++ = *src;
63         } else if (isspace(*src)) {
64             if (*argv[argc]) {
65                 buf++, argc++;
66                 if (argc == argvAlloced) {
67                     argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
68                     argv = realloc(argv, sizeof(*argv) * argvAlloced);
69                 }
70                 argv[argc] = buf;
71             }
72         } else switch (*src) {
73           case '"':
74           case '\'':
75             quote = *src;
76             break;
77           case '\\':
78             src++;
79             if (!*src) {
80                 free(argv);
81                 return POPT_ERROR_BADQUOTE;
82             }
83             /*@fallthrough@*/
84           default:
85             *buf++ = *src;
86             break;
87         }
88     }
89
90     if (strlen(argv[argc])) {
91         argc++, buf++;
92     }
93
94     (void) poptDupArgv(argc, argv, argcPtr, argvPtr);
95
96     free(argv);
97
98     return 0;
99 }