Merge branch 'singlecompression' into single
[kai/samba-autobuild/.git] / lib / popt / poptparse.c
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
13 /*@-boundswrite@*/
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
22     if (argc <= 0 || argv == NULL)      /* XXX can't happen */
23         return POPT_ERROR_NOARG;
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 = (char *)malloc(nb);
31     if (dst == NULL)                    /* XXX can't happen */
32         return POPT_ERROR_MALLOC;
33     argv2 = (const char **) dst;
34     dst += (argc + 1) * sizeof(*argv);
35
36     /*@-branchstate@*/
37     for (i = 0; i < argc; i++) {
38         argv2[i] = dst;
39         dst += strlen(strcpy(dst, argv[i])) + 1;
40     }
41     /*@=branchstate@*/
42     argv2[argc] = NULL;
43
44     if (argvPtr) {
45         *argvPtr = argv2;
46     } else {
47         free(argv2);
48         argv2 = NULL;
49     }
50     if (argcPtr)
51         *argcPtr = argc;
52     return 0;
53 }
54 /*@=boundswrite@*/
55
56 /*@-bounds@*/
57 int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
58 {
59     const char * src;
60     char quote = '\0';
61     int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
62     const char ** argv = (const char **)malloc(sizeof(*argv) * argvAlloced);
63     int argc = 0;
64     int buflen = strlen(s) + 1;
65     char * buf = (char*)memset(alloca(buflen), 0, buflen);
66     int rc = POPT_ERROR_MALLOC;
67
68     if (argv == NULL) return rc;
69     argv[argc] = buf;
70
71     for (src = s; *src != '\0'; src++) {
72         if (quote == *src) {
73             quote = '\0';
74         } else if (quote != '\0') {
75             if (*src == '\\') {
76                 src++;
77                 if (!*src) {
78                     rc = POPT_ERROR_BADQUOTE;
79                     goto exit;
80                 }
81                 if (*src != quote) *buf++ = '\\';
82             }
83             *buf++ = *src;
84         } else if (isspace(*src)) {
85             if (*argv[argc] != '\0') {
86                 buf++, argc++;
87                 if (argc == argvAlloced) {
88                     argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
89                     argv = (const char **)realloc(argv, sizeof(*argv) * argvAlloced);
90                     if (argv == NULL) goto exit;
91                 }
92                 argv[argc] = buf;
93             }
94         } else switch (*src) {
95           case '"':
96           case '\'':
97             quote = *src;
98             /*@switchbreak@*/ break;
99           case '\\':
100             src++;
101             if (!*src) {
102                 rc = POPT_ERROR_BADQUOTE;
103                 goto exit;
104             }
105             /*@fallthrough@*/
106           default:
107             *buf++ = *src;
108             /*@switchbreak@*/ break;
109         }
110     }
111
112     if (strlen(argv[argc])) {
113         argc++, buf++;
114     }
115
116     rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
117
118 exit:
119     if (argv) free(argv);
120     return rc;
121 }
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@*/ 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 = (char *)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 = (char *)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 = (char *)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 }