Commit | Line | Data |
---|---|---|
cc248aae WD |
1 | /** \ingroup popt |
2 | * \file popt/poptparse.c | |
3 | */ | |
4 | ||
bc93ee84 | 5 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING |
62402cb1 | 6 | file accompanying popt source distributions, available from |
cc248aae | 7 | ftp://ftp.rpm.org/pub/rpm/dist. */ |
62402cb1 | 8 | |
b348deae | 9 | #include "system.h" |
62402cb1 | 10 | |
a8facdc0 WD |
11 | #include "poptint.h" |
12 | ||
b348deae | 13 | #define POPT_ARGV_ARRAY_GROW_DELTA 5 |
62402cb1 | 14 | |
bc93ee84 | 15 | /*@-boundswrite@*/ |
b348deae MP |
16 | int poptDupArgv(int argc, const char **argv, |
17 | int * argcPtr, const char *** argvPtr) | |
18 | { | |
19 | size_t nb = (argc + 1) * sizeof(*argv); | |
20 | const char ** argv2; | |
21 | char * dst; | |
22 | int i; | |
23 | ||
cc248aae WD |
24 | if (argc <= 0 || argv == NULL) /* XXX can't happen */ |
25 | return POPT_ERROR_NOARG; | |
b348deae MP |
26 | for (i = 0; i < argc; i++) { |
27 | if (argv[i] == NULL) | |
28 | return POPT_ERROR_NOARG; | |
29 | nb += strlen(argv[i]) + 1; | |
30 | } | |
31 | ||
32 | dst = malloc(nb); | |
cc248aae WD |
33 | if (dst == NULL) /* XXX can't happen */ |
34 | return POPT_ERROR_MALLOC; | |
b348deae MP |
35 | argv2 = (void *) dst; |
36 | dst += (argc + 1) * sizeof(*argv); | |
37 | ||
cc248aae | 38 | /*@-branchstate@*/ |
b348deae MP |
39 | for (i = 0; i < argc; i++) { |
40 | argv2[i] = dst; | |
bc93ee84 | 41 | dst += strlcpy(dst, argv[i], nb) + 1; |
b348deae | 42 | } |
cc248aae | 43 | /*@=branchstate@*/ |
b348deae MP |
44 | argv2[argc] = NULL; |
45 | ||
cc248aae WD |
46 | if (argvPtr) { |
47 | *argvPtr = argv2; | |
48 | } else { | |
49 | free(argv2); | |
50 | argv2 = NULL; | |
51 | } | |
52 | if (argcPtr) | |
53 | *argcPtr = argc; | |
b348deae MP |
54 | return 0; |
55 | } | |
bc93ee84 | 56 | /*@=boundswrite@*/ |
62402cb1 | 57 | |
bc93ee84 WD |
58 | /*@-bounds@*/ |
59 | int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) | |
b348deae | 60 | { |
bc93ee84 WD |
61 | const char * src; |
62 | char quote = '\0'; | |
b348deae MP |
63 | int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; |
64 | const char ** argv = malloc(sizeof(*argv) * argvAlloced); | |
62402cb1 | 65 | int argc = 0; |
b348deae | 66 | int buflen = strlen(s) + 1; |
cc248aae WD |
67 | char * buf = memset(alloca(buflen), 0, buflen); |
68 | int rc = POPT_ERROR_MALLOC; | |
62402cb1 | 69 | |
cc248aae | 70 | if (argv == NULL) return rc; |
62402cb1 MP |
71 | argv[argc] = buf; |
72 | ||
cc248aae | 73 | for (src = s; *src != '\0'; src++) { |
62402cb1 MP |
74 | if (quote == *src) { |
75 | quote = '\0'; | |
cc248aae | 76 | } else if (quote != '\0') { |
62402cb1 MP |
77 | if (*src == '\\') { |
78 | src++; | |
79 | if (!*src) { | |
cc248aae WD |
80 | rc = POPT_ERROR_BADQUOTE; |
81 | goto exit; | |
62402cb1 MP |
82 | } |
83 | if (*src != quote) *buf++ = '\\'; | |
84 | } | |
85 | *buf++ = *src; | |
a8facdc0 | 86 | } else if (isSpace(src)) { |
cc248aae | 87 | if (*argv[argc] != '\0') { |
62402cb1 MP |
88 | buf++, argc++; |
89 | if (argc == argvAlloced) { | |
b348deae | 90 | argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; |
62402cb1 | 91 | argv = realloc(argv, sizeof(*argv) * argvAlloced); |
cc248aae | 92 | if (argv == NULL) goto exit; |
62402cb1 MP |
93 | } |
94 | argv[argc] = buf; | |
95 | } | |
96 | } else switch (*src) { | |
97 | case '"': | |
98 | case '\'': | |
99 | quote = *src; | |
cc248aae | 100 | /*@switchbreak@*/ break; |
62402cb1 MP |
101 | case '\\': |
102 | src++; | |
103 | if (!*src) { | |
cc248aae WD |
104 | rc = POPT_ERROR_BADQUOTE; |
105 | goto exit; | |
62402cb1 | 106 | } |
b348deae | 107 | /*@fallthrough@*/ |
62402cb1 MP |
108 | default: |
109 | *buf++ = *src; | |
cc248aae | 110 | /*@switchbreak@*/ break; |
62402cb1 | 111 | } |
62402cb1 MP |
112 | } |
113 | ||
114 | if (strlen(argv[argc])) { | |
115 | argc++, buf++; | |
116 | } | |
117 | ||
cc248aae | 118 | rc = poptDupArgv(argc, argv, argcPtr, argvPtr); |
62402cb1 | 119 | |
cc248aae WD |
120 | exit: |
121 | if (argv) free(argv); | |
122 | return rc; | |
62402cb1 | 123 | } |
bc93ee84 WD |
124 | /*@=bounds@*/ |
125 | ||
126 | /* still in the dev stage. | |
127 | * return values, perhaps 1== file erro | |
128 | * 2== line to long | |
129 | * 3== umm.... more? | |
130 | */ | |
131 | int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags)) | |
132 | { | |
133 | char line[999]; | |
134 | char * argstr; | |
135 | char * p; | |
136 | char * q; | |
137 | char * x; | |
138 | int t; | |
139 | int argvlen = 0; | |
140 | size_t maxlinelen = sizeof(line); | |
141 | size_t linelen; | |
142 | int maxargvlen = 480; | |
143 | int linenum = 0; | |
144 | ||
145 | *argstrp = NULL; | |
146 | ||
147 | /* | this_is = our_line | |
148 | * p q x | |
149 | */ | |
150 | ||
151 | if (fp == NULL) | |
152 | return POPT_ERROR_NULLARG; | |
153 | ||
154 | argstr = calloc(maxargvlen, sizeof(*argstr)); | |
155 | if (argstr == NULL) return POPT_ERROR_MALLOC; | |
156 | ||
157 | while (fgets(line, (int)maxlinelen, fp) != NULL) { | |
158 | linenum++; | |
159 | p = line; | |
160 | ||
161 | /* loop until first non-space char or EOL */ | |
a8facdc0 | 162 | while( *p != '\0' && isSpace(p) ) |
bc93ee84 WD |
163 | p++; |
164 | ||
165 | linelen = strlen(p); | |
166 | if (linelen >= maxlinelen-1) | |
167 | return POPT_ERROR_OVERFLOW; /* XXX line too long */ | |
168 | ||
169 | if (*p == '\0' || *p == '\n') continue; /* line is empty */ | |
170 | if (*p == '#') continue; /* comment line */ | |
171 | ||
172 | q = p; | |
173 | ||
a8facdc0 | 174 | while (*q != '\0' && (!isSpace(q)) && *q != '=') |
bc93ee84 WD |
175 | q++; |
176 | ||
a8facdc0 | 177 | if (isSpace(q)) { |
bc93ee84 WD |
178 | /* a space after the name, find next non space */ |
179 | *q++='\0'; | |
a8facdc0 | 180 | while( *q != '\0' && isSpace(q) ) q++; |
bc93ee84 WD |
181 | } |
182 | if (*q == '\0') { | |
183 | /* single command line option (ie, no name=val, just name) */ | |
184 | q[-1] = '\0'; /* kill off newline from fgets() call */ | |
185 | argvlen += (t = q - p) + (sizeof(" --")-1); | |
186 | if (argvlen >= maxargvlen) { | |
187 | maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; | |
188 | argstr = realloc(argstr, maxargvlen); | |
189 | if (argstr == NULL) return POPT_ERROR_MALLOC; | |
190 | } | |
a19d285a WD |
191 | strlcat(argstr, " --", maxargvlen); |
192 | strlcat(argstr, p, maxargvlen); | |
bc93ee84 WD |
193 | continue; |
194 | } | |
195 | if (*q != '=') | |
196 | continue; /* XXX for now, silently ignore bogus line */ | |
197 | ||
198 | /* *q is an equal sign. */ | |
199 | *q++ = '\0'; | |
200 | ||
201 | /* find next non-space letter of value */ | |
a8facdc0 | 202 | while (*q != '\0' && isSpace(q)) |
bc93ee84 WD |
203 | q++; |
204 | if (*q == '\0') | |
205 | continue; /* XXX silently ignore missing value */ | |
206 | ||
207 | /* now, loop and strip all ending whitespace */ | |
208 | x = p + linelen; | |
a8facdc0 | 209 | while (isSpace(--x)) |
bc93ee84 WD |
210 | *x = 0; /* null out last char if space (including fgets() NL) */ |
211 | ||
212 | /* rest of line accept */ | |
213 | t = x - p; | |
214 | argvlen += t + (sizeof("' --='")-1); | |
215 | if (argvlen >= maxargvlen) { | |
216 | maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; | |
217 | argstr = realloc(argstr, maxargvlen); | |
218 | if (argstr == NULL) return POPT_ERROR_MALLOC; | |
219 | } | |
a19d285a WD |
220 | strlcat(argstr, " --", maxargvlen); |
221 | strlcat(argstr, p, maxargvlen); | |
222 | strlcat(argstr, "=\"", maxargvlen); | |
223 | strlcat(argstr, q, maxargvlen); | |
224 | strlcat(argstr, "\"", maxargvlen); | |
bc93ee84 WD |
225 | } |
226 | ||
227 | *argstrp = argstr; | |
228 | return 0; | |
229 | } |