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