Home | History | Annotate | Download | only in libpopt
      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