1 /** \ingroup popt
2  * \file popt/poptparse.c
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 
poptDupArgv(int argc,const char ** argv,int * argcPtr,const char *** argvPtr)13 int 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 
poptParseArgvString(const char * s,int * argcPtr,const char *** argvPtr)54 int 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     int argc = 0;
61     size_t buflen = strlen(s) + 1;
62     char * buf, * bufOrig = NULL;
63     int rc = POPT_ERROR_MALLOC;
64 
65     if (argv == NULL) return rc;
66     buf = bufOrig = calloc((size_t)1, buflen);
67     if (buf == NULL) {
68 	free(argv);
69 	return rc;
70     }
71     argv[argc] = buf;
72 
73     for (src = s; *src != '\0'; src++) {
74 	if (quote == *src) {
75 	    quote = '\0';
76 	} else if (quote != '\0') {
77 	    if (*src == '\\') {
78 		src++;
79 		if (!*src) {
80 		    rc = POPT_ERROR_BADQUOTE;
81 		    goto exit;
82 		}
83 		if (*src != quote) *buf++ = '\\';
84 	    }
85 	    *buf++ = *src;
86 	} else if (_isspaceptr(src)) {
87 	    if (*argv[argc] != '\0') {
88 		buf++, argc++;
89 		if (argc == argvAlloced) {
90 		    argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
91 		    argv = realloc(argv, sizeof(*argv) * argvAlloced);
92 		    if (argv == NULL) goto exit;
93 		}
94 		argv[argc] = buf;
95 	    }
96 	} else switch (*src) {
97 	  case '"':
98 	  case '\'':
99 	    quote = *src;
100 	    break;
101 	  case '\\':
102 	    src++;
103 	    if (!*src) {
104 		rc = POPT_ERROR_BADQUOTE;
105 		goto exit;
106 	    }
107 	    /* fallthrough */
108 	  default:
109 	    *buf++ = *src;
110 	    break;
111 	}
112     }
113 
114     if (strlen(argv[argc])) {
115 	argc++, buf++;
116     }
117 
118     rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
119 
120 exit:
121     if (bufOrig) free(bufOrig);
122     if (argv) free(argv);
123     return rc;
124 }
125 
126 /* still in the dev stage.
127  * return values, perhaps 1== file erro
128  * 2== line to long
129  * 3== umm.... more?
130  */
poptConfigFileToString(FILE * fp,char ** argstrp,UNUSED (int flags))131 int poptConfigFileToString(FILE *fp, char ** argstrp,
132 		UNUSED(int flags))
133 {
134     char line[999];
135     char * argstr;
136     char * p;
137     char * q;
138     char * x;
139     size_t t;
140     size_t argvlen = 0;
141     size_t maxlinelen = sizeof(line);
142     size_t linelen;
143     size_t maxargvlen = (size_t)480;
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 	p = line;
159 
160 	/* loop until first non-space char or EOL */
161 	while( *p != '\0' && _isspaceptr(p) )
162 	    p++;
163 
164 	linelen = strlen(p);
165 	if (linelen >= maxlinelen-1) {
166 	    free(argstr);
167 	    return POPT_ERROR_OVERFLOW;	/* XXX line too long */
168 	}
169 
170 	if (*p == '\0' || *p == '\n') continue;	/* line is empty */
171 	if (*p == '#') continue;		/* comment line */
172 
173 	q = p;
174 
175 	while (*q != '\0' && (!_isspaceptr(q)) && *q != '=')
176 	    q++;
177 
178 	if (_isspaceptr(q)) {
179 	    /* a space after the name, find next non space */
180 	    *q++='\0';
181 	    while( *q != '\0' && _isspaceptr(q) ) q++;
182 	}
183 	if (*q == '\0') {
184 	    /* single command line option (ie, no name=val, just name) */
185 	    q[-1] = '\0';		/* kill off newline from fgets() call */
186 	    argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1);
187 	    if (argvlen >= maxargvlen) {
188 		maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
189 		argstr = realloc(argstr, maxargvlen);
190 		if (argstr == NULL) return POPT_ERROR_MALLOC;
191 	    }
192 	    strcat(argstr, " --");
193 	    strcat(argstr, p);
194 	    continue;
195 	}
196 	if (*q != '=')
197 	    continue;	/* XXX for now, silently ignore bogus line */
198 
199 	/* *q is an equal sign. */
200 	*q++ = '\0';
201 
202 	/* find next non-space letter of value */
203 	while (*q != '\0' && _isspaceptr(q))
204 	    q++;
205 	if (*q == '\0')
206 	    continue;	/* XXX silently ignore missing value */
207 
208 	/* now, loop and strip all ending whitespace */
209 	x = p + linelen;
210 	while (_isspaceptr(--x))
211 	    *x = '\0';	/* null out last char if space (including fgets() NL) */
212 
213 	/* rest of line accept */
214 	t = (size_t)(x - p);
215 	argvlen += t + (sizeof("' --='")-1);
216 	if (argvlen >= maxargvlen) {
217 	    maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
218 	    argstr = realloc(argstr, maxargvlen);
219 	    if (argstr == NULL) return POPT_ERROR_MALLOC;
220 	}
221 	strcat(argstr, " --");
222 	strcat(argstr, p);
223 	strcat(argstr, "=\"");
224 	strcat(argstr, q);
225 	strcat(argstr, "\"");
226     }
227 
228     *argstrp = argstr;
229     return 0;
230 }
231