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 = malloc(nb); 31 if (dst == NULL) /* XXX can't happen */ 32 return POPT_ERROR_MALLOC; 33 argv2 = (void *) 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 = malloc(sizeof(*argv) * argvAlloced); 63 int argc = 0; 64 int buflen = strlen(s) + 1; 65 char * buf = 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 = 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 = 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 } 228