Need to include lib/snprintf.o when building wildtest.
[rsync/rsync.git] / popt / poptparse.c
CommitLineData
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
14int 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@*/
57int 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
118exit:
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 */
129int 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}