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