Always check old==new, even for missing array size.
[rsync.git] / popt / poptparse.c
blob5afc6c551f83ca4f2675435bf1bc1e0fe9721b96
1 /** \ingroup popt
2 * @file
3 */
5 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
6 file accompanying popt source distributions, available from
7 ftp://ftp.rpm.org/pub/rpm/dist. */
9 #include "system.h"
11 #define POPT_ARGV_ARRAY_GROW_DELTA 5
13 int poptDupArgv(int argc, const char **argv,
14 int * argcPtr, const char *** argvPtr)
16 size_t nb = (argc + 1) * sizeof(*argv);
17 const char ** argv2;
18 char * dst;
19 int i;
21 if (argc <= 0 || argv == NULL) /* XXX can't happen */
22 return POPT_ERROR_NOARG;
23 for (i = 0; i < argc; i++) {
24 if (argv[i] == NULL)
25 return POPT_ERROR_NOARG;
26 nb += strlen(argv[i]) + 1;
29 dst = malloc(nb);
30 if (dst == NULL) /* XXX can't happen */
31 return POPT_ERROR_MALLOC;
32 argv2 = (void *) dst;
33 dst += (argc + 1) * sizeof(*argv);
34 *dst = '\0';
36 for (i = 0; i < argc; i++) {
37 argv2[i] = dst;
38 dst = stpcpy(dst, argv[i]);
39 dst++; /* trailing NUL */
41 argv2[argc] = NULL;
43 if (argvPtr) {
44 *argvPtr = argv2;
45 } else {
46 free(argv2);
47 argv2 = NULL;
49 if (argcPtr)
50 *argcPtr = argc;
51 return 0;
54 int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
56 const char * src;
57 char quote = '\0';
58 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
59 const char ** argv = malloc(sizeof(*argv) * argvAlloced);
60 const char ** argv_tmp;
61 int argc = 0;
62 size_t buflen = strlen(s) + 1;
63 char * buf, * bufOrig = NULL;
64 int rc = POPT_ERROR_MALLOC;
66 if (argv == NULL) return rc;
67 buf = bufOrig = calloc((size_t)1, buflen);
68 if (buf == NULL) {
69 free(argv);
70 return rc;
72 argv[argc] = buf;
74 for (src = s; *src != '\0'; src++) {
75 if (quote == *src) {
76 quote = '\0';
77 } else if (quote != '\0') {
78 if (*src == '\\') {
79 src++;
80 if (!*src) {
81 rc = POPT_ERROR_BADQUOTE;
82 goto exit;
84 if (*src != quote) *buf++ = '\\';
86 *buf++ = *src;
87 } else if (_isspaceptr(src)) {
88 if (*argv[argc] != '\0') {
89 buf++, argc++;
90 if (argc == argvAlloced) {
91 argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
92 argv_tmp = realloc(argv, sizeof(*argv) * argvAlloced);
93 if (argv_tmp == NULL) goto exit;
94 argv = argv_tmp;
96 argv[argc] = buf;
98 } else switch (*src) {
99 case '"':
100 case '\'':
101 quote = *src;
102 break;
103 case '\\':
104 src++;
105 if (!*src) {
106 rc = POPT_ERROR_BADQUOTE;
107 goto exit;
109 /* fallthrough */
110 default:
111 *buf++ = *src;
112 break;
116 if (strlen(argv[argc])) {
117 argc++, buf++;
120 rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
122 exit:
123 if (bufOrig) free(bufOrig);
124 if (argv) free(argv);
125 return rc;
128 /* still in the dev stage.
129 * return values, perhaps 1== file error
130 * 2== line to long
131 * 3== umm.... more?
133 int poptConfigFileToString(FILE *fp, char ** argstrp,
134 UNUSED(int flags))
136 char line[999];
137 char * argstr;
138 char * argstr_tmp;
139 char * p;
140 char * q;
141 char * x;
142 size_t t;
143 size_t argvlen = 0;
144 size_t maxlinelen = sizeof(line);
145 size_t linelen;
146 size_t maxargvlen = (size_t)480;
148 *argstrp = NULL;
150 /* | this_is = our_line
151 * p q x
154 if (fp == NULL)
155 return POPT_ERROR_NULLARG;
157 argstr = calloc(maxargvlen, sizeof(*argstr));
158 if (argstr == NULL) return POPT_ERROR_MALLOC;
160 while (fgets(line, (int)maxlinelen, fp) != NULL) {
161 p = line;
163 /* loop until first non-space char or EOL */
164 while( *p != '\0' && _isspaceptr(p) )
165 p++;
167 linelen = strlen(p);
168 if (linelen >= maxlinelen-1) {
169 free(argstr);
170 return POPT_ERROR_OVERFLOW; /* XXX line too long */
173 if (*p == '\0' || *p == '\n') continue; /* line is empty */
174 if (*p == '#') continue; /* comment line */
176 q = p;
178 while (*q != '\0' && (!_isspaceptr(q)) && *q != '=')
179 q++;
181 if (_isspaceptr(q)) {
182 /* a space after the name, find next non space */
183 *q++='\0';
184 while( *q != '\0' && _isspaceptr(q) ) q++;
186 if (*q == '\0') {
187 /* single command line option (ie, no name=val, just name) */
188 q[-1] = '\0'; /* kill off newline from fgets() call */
189 argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1);
190 if (argvlen >= maxargvlen) {
191 maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
192 argstr_tmp = realloc(argstr, maxargvlen);
193 if (argstr_tmp == NULL) {
194 free(argstr);
195 return POPT_ERROR_MALLOC;
197 argstr = argstr_tmp;
199 strcat(argstr, " --");
200 strcat(argstr, p);
201 continue;
203 if (*q != '=')
204 continue; /* XXX for now, silently ignore bogus line */
206 /* *q is an equal sign. */
207 *q++ = '\0';
209 /* find next non-space letter of value */
210 while (*q != '\0' && _isspaceptr(q))
211 q++;
212 if (*q == '\0')
213 continue; /* XXX silently ignore missing value */
215 /* now, loop and strip all ending whitespace */
216 x = p + linelen;
217 while (_isspaceptr(--x))
218 *x = '\0'; /* null out last char if space (including fgets() NL) */
220 /* rest of line accept */
221 t = (size_t)(x - p);
222 argvlen += t + (sizeof("' --='")-1);
223 if (argvlen >= maxargvlen) {
224 maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
225 argstr_tmp = realloc(argstr, maxargvlen);
226 if (argstr_tmp == NULL) {
227 free(argstr);
228 return POPT_ERROR_MALLOC;
230 argstr = argstr_tmp;
232 strcat(argstr, " --");
233 strcat(argstr, p);
234 strcat(argstr, "=\"");
235 strcat(argstr, q);
236 strcat(argstr, "\"");
239 *argstrp = argstr;
240 return 0;