| /** \ingroup popt |
| * \file popt/poptparse.c |
| */ |
| |
| /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING |
| file accompanying popt source distributions, available from |
| ftp://ftp.rpm.org/pub/rpm/dist. */ |
| |
| #include "system.h" |
| |
| #define POPT_ARGV_ARRAY_GROW_DELTA 5 |
| |
| int poptDupArgv(int argc, const char **argv, |
| int * argcPtr, const char *** argvPtr) |
| { |
| size_t nb = (argc + 1) * sizeof(*argv); |
| const char ** argv2; |
| char * dst; |
| int i; |
| |
| if (argc <= 0 || argv == NULL) /* XXX can't happen */ |
| return POPT_ERROR_NOARG; |
| for (i = 0; i < argc; i++) { |
| if (argv[i] == NULL) |
| return POPT_ERROR_NOARG; |
| nb += strlen(argv[i]) + 1; |
| } |
| |
| dst = malloc(nb); |
| if (dst == NULL) /* XXX can't happen */ |
| return POPT_ERROR_MALLOC; |
| argv2 = (void *) dst; |
| dst += (argc + 1) * sizeof(*argv); |
| *dst = '\0'; |
| |
| for (i = 0; i < argc; i++) { |
| argv2[i] = dst; |
| dst = stpcpy(dst, argv[i]); |
| dst++; /* trailing NUL */ |
| } |
| argv2[argc] = NULL; |
| |
| if (argvPtr) { |
| *argvPtr = argv2; |
| } else { |
| free(argv2); |
| argv2 = NULL; |
| } |
| if (argcPtr) |
| *argcPtr = argc; |
| return 0; |
| } |
| |
| int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) |
| { |
| const char * src; |
| char quote = '\0'; |
| int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; |
| const char ** argv = malloc(sizeof(*argv) * argvAlloced); |
| int argc = 0; |
| size_t buflen = strlen(s) + 1; |
| char * buf, * bufOrig = NULL; |
| int rc = POPT_ERROR_MALLOC; |
| |
| if (argv == NULL) return rc; |
| buf = bufOrig = calloc((size_t)1, buflen); |
| if (buf == NULL) { |
| free(argv); |
| return rc; |
| } |
| argv[argc] = buf; |
| |
| for (src = s; *src != '\0'; src++) { |
| if (quote == *src) { |
| quote = '\0'; |
| } else if (quote != '\0') { |
| if (*src == '\\') { |
| src++; |
| if (!*src) { |
| rc = POPT_ERROR_BADQUOTE; |
| goto exit; |
| } |
| if (*src != quote) *buf++ = '\\'; |
| } |
| *buf++ = *src; |
| } else if (_isspaceptr(src)) { |
| if (*argv[argc] != '\0') { |
| buf++, argc++; |
| if (argc == argvAlloced) { |
| argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; |
| argv = realloc(argv, sizeof(*argv) * argvAlloced); |
| if (argv == NULL) goto exit; |
| } |
| argv[argc] = buf; |
| } |
| } else switch (*src) { |
| case '"': |
| case '\'': |
| quote = *src; |
| /*@switchbreak@*/ break; |
| case '\\': |
| src++; |
| if (!*src) { |
| rc = POPT_ERROR_BADQUOTE; |
| goto exit; |
| } |
| /*@fallthrough@*/ |
| default: |
| *buf++ = *src; |
| /*@switchbreak@*/ break; |
| } |
| } |
| |
| if (strlen(argv[argc])) { |
| argc++, buf++; |
| } |
| |
| rc = poptDupArgv(argc, argv, argcPtr, argvPtr); |
| |
| exit: |
| if (bufOrig) free(bufOrig); |
| if (argv) free(argv); |
| return rc; |
| } |
| |
| /* still in the dev stage. |
| * return values, perhaps 1== file erro |
| * 2== line to long |
| * 3== umm.... more? |
| */ |
| int poptConfigFileToString(FILE *fp, char ** argstrp, |
| /*@unused@*/ UNUSED(int flags)) |
| { |
| char line[999]; |
| char * argstr; |
| char * p; |
| char * q; |
| char * x; |
| size_t t; |
| size_t argvlen = 0; |
| size_t maxlinelen = sizeof(line); |
| size_t linelen; |
| size_t maxargvlen = (size_t)480; |
| |
| *argstrp = NULL; |
| |
| /* | this_is = our_line |
| * p q x |
| */ |
| |
| if (fp == NULL) |
| return POPT_ERROR_NULLARG; |
| |
| argstr = calloc(maxargvlen, sizeof(*argstr)); |
| if (argstr == NULL) return POPT_ERROR_MALLOC; |
| |
| while (fgets(line, (int)maxlinelen, fp) != NULL) { |
| p = line; |
| |
| /* loop until first non-space char or EOL */ |
| while( *p != '\0' && _isspaceptr(p) ) |
| p++; |
| |
| linelen = strlen(p); |
| if (linelen >= maxlinelen-1) { |
| free(argstr); |
| return POPT_ERROR_OVERFLOW; /* XXX line too long */ |
| } |
| |
| if (*p == '\0' || *p == '\n') continue; /* line is empty */ |
| if (*p == '#') continue; /* comment line */ |
| |
| q = p; |
| |
| while (*q != '\0' && (!_isspaceptr(q)) && *q != '=') |
| q++; |
| |
| if (_isspaceptr(q)) { |
| /* a space after the name, find next non space */ |
| *q++='\0'; |
| while( *q != '\0' && _isspaceptr(q) ) q++; |
| } |
| if (*q == '\0') { |
| /* single command line option (ie, no name=val, just name) */ |
| q[-1] = '\0'; /* kill off newline from fgets() call */ |
| argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1); |
| if (argvlen >= maxargvlen) { |
| maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; |
| argstr = realloc(argstr, maxargvlen); |
| if (argstr == NULL) return POPT_ERROR_MALLOC; |
| } |
| strcat(argstr, " --"); |
| strcat(argstr, p); |
| continue; |
| } |
| if (*q != '=') |
| continue; /* XXX for now, silently ignore bogus line */ |
| |
| /* *q is an equal sign. */ |
| *q++ = '\0'; |
| |
| /* find next non-space letter of value */ |
| while (*q != '\0' && _isspaceptr(q)) |
| q++; |
| if (*q == '\0') |
| continue; /* XXX silently ignore missing value */ |
| |
| /* now, loop and strip all ending whitespace */ |
| x = p + linelen; |
| while (_isspaceptr(--x)) |
| *x = '\0'; /* null out last char if space (including fgets() NL) */ |
| |
| /* rest of line accept */ |
| t = (size_t)(x - p); |
| argvlen += t + (sizeof("' --='")-1); |
| if (argvlen >= maxargvlen) { |
| maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; |
| argstr = realloc(argstr, maxargvlen); |
| if (argstr == NULL) return POPT_ERROR_MALLOC; |
| } |
| strcat(argstr, " --"); |
| strcat(argstr, p); |
| strcat(argstr, "=\""); |
| strcat(argstr, q); |
| strcat(argstr, "\""); |
| } |
| |
| *argstrp = argstr; |
| return 0; |
| } |