xref: /third_party/popt/src/poptparse.c (revision 9f07849e)
1/** \ingroup popt
2 * @file
3 */
4
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. */
8
9#include "system.h"
10
11#define POPT_ARGV_ARRAY_GROW_DELTA 5
12
13int poptDupArgv(int argc, const char **argv,
14		int * argcPtr, const char *** argvPtr)
15{
16    size_t nb = (argc + 1) * sizeof(*argv);
17    const char ** argv2;
18    char * dst;
19    int i;
20
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;
27    }
28
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';
35
36    for (i = 0; i < argc; i++) {
37	argv2[i] = dst;
38	dst = stpcpy(dst, argv[i]);
39	dst++;	/* trailing NUL */
40    }
41    argv2[argc] = NULL;
42
43    if (argvPtr) {
44	*argvPtr = argv2;
45    } else {
46	free(argv2);
47	argv2 = NULL;
48    }
49    if (argcPtr)
50	*argcPtr = argc;
51    return 0;
52}
53
54int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
55{
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;
65
66    if (argv == NULL) return rc;
67    buf = bufOrig = calloc((size_t)1, buflen);
68    if (buf == NULL) {
69	free(argv);
70	return rc;
71    }
72    argv[argc] = buf;
73
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;
83		}
84		if (*src != quote) *buf++ = '\\';
85	    }
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;
95		}
96		argv[argc] = buf;
97	    }
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;
108	    }
109	    /* fallthrough */
110	  default:
111	    *buf++ = *src;
112	    break;
113	}
114    }
115
116    if (strlen(argv[argc])) {
117	argc++, buf++;
118    }
119
120    rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
121
122exit:
123    if (bufOrig) free(bufOrig);
124    if (argv) free(argv);
125    return rc;
126}
127
128/* still in the dev stage.
129 * return values, perhaps 1== file error
130 * 2== line to long
131 * 3== umm.... more?
132 */
133int poptConfigFileToString(FILE *fp, char ** argstrp,
134		UNUSED(int flags))
135{
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;
147
148    *argstrp = NULL;
149
150    /*   |   this_is   =   our_line
151     *	     p             q      x
152     */
153
154    if (fp == NULL)
155	return POPT_ERROR_NULLARG;
156
157    argstr = calloc(maxargvlen, sizeof(*argstr));
158    if (argstr == NULL) return POPT_ERROR_MALLOC;
159
160    while (fgets(line, (int)maxlinelen, fp) != NULL) {
161	p = line;
162
163	/* loop until first non-space char or EOL */
164	while( *p != '\0' && _isspaceptr(p) )
165	    p++;
166
167	linelen = strlen(p);
168	if (linelen >= maxlinelen-1) {
169	    free(argstr);
170	    return POPT_ERROR_OVERFLOW;	/* XXX line too long */
171	}
172
173	if (*p == '\0' || *p == '\n') continue;	/* line is empty */
174	if (*p == '#') continue;		/* comment line */
175
176	q = p;
177
178	while (*q != '\0' && (!_isspaceptr(q)) && *q != '=')
179	    q++;
180
181	if (_isspaceptr(q)) {
182	    /* a space after the name, find next non space */
183	    *q++='\0';
184	    while( *q != '\0' && _isspaceptr(q) ) q++;
185	}
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;
196		}
197		argstr = argstr_tmp;
198	    }
199	    strcat(argstr, " --");
200	    strcat(argstr, p);
201	    continue;
202	}
203	if (*q != '=')
204	    continue;	/* XXX for now, silently ignore bogus line */
205
206	/* *q is an equal sign. */
207	*q++ = '\0';
208
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 */
214
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) */
219
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;
229	    }
230	    argstr = argstr_tmp;
231	}
232	strcat(argstr, " --");
233	strcat(argstr, p);
234	strcat(argstr, "=\"");
235	strcat(argstr, q);
236	strcat(argstr, "\"");
237    }
238
239    *argstrp = argstr;
240    return 0;
241}
242