/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */ static int poptConfigLine(poptContext con, char * line) /*@globals fileSystem, internalState @*/ /*@modifies con, fileSystem, internalState @*/ { char *b = NULL; size_t nb = 0; char * se = line; const char * appName; const char * entryType; const char * opt; struct poptItem_s item_buf; poptItem item = &item_buf; int i, j; int rc = POPT_ERROR_BADCONFIG; if (con->appName == NULL) goto exit; memset(item, 0, sizeof(*item)); appName = se; while (*se != '\0' && !_isspaceptr(se)) se++; if (*se == '\0') goto exit; else *se++ = '\0'; if (configAppMatch(con, appName)) goto exit; while (*se != '\0' && _isspaceptr(se)) se++; entryType = se; while (*se != '\0' && !_isspaceptr(se)) se++; if (*se != '\0') *se++ = '\0'; while (*se != '\0' && _isspaceptr(se)) se++; if (*se == '\0') goto exit; opt = se; while (*se != '\0' && !_isspaceptr(se)) se++; if (opt[0] == '-' && *se == '\0') goto exit; if (*se != '\0') *se++ = '\0'; while (*se != '\0' && _isspaceptr(se)) se++; if (opt[0] == '-' && *se == '\0') goto exit; /*@-temptrans@*/ /* FIX: line alias is saved */ if (opt[0] == '-' && opt[1] == '-') item->option.longName = opt + 2; else if (opt[0] == '-' && opt[2] == '\0') item->option.shortName = opt[1]; else { const char * fn = opt; /* XXX handle globs and directories in fn? */ if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0) goto exit; if (b == NULL || nb == 0) goto exit; /* Append remaining text to the interpolated file option text. */ if (*se != '\0') { size_t nse = strlen(se) + 1; if ((b = realloc(b, (nb + nse))) == NULL) /* XXX can't happen */ goto exit; (void) stpcpy( stpcpy(&b[nb-1], " "), se); nb += nse; } se = b; /* Use the basename of the path as the long option name. */ { const char * longName = strrchr(fn, '/'); if (longName != NULL) longName++; else longName = fn; if (longName == NULL) /* XXX can't happen. */ goto exit; /* Single character basenames are treated as short options. */ if (longName[1] != '\0') item->option.longName = longName; else item->option.shortName = longName[0]; } } /*@=temptrans@*/ if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit; /*@-modobserver@*/ item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; for (i = 0, j = 0; i < item->argc; i++, j++) { const char * f; if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) { f = item->argv[i] + sizeof("--POPTdesc="); if (f[0] == '$' && f[1] == '"') f++; item->option.descrip = f; item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; j--; } else if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) { f = item->argv[i] + sizeof("--POPTargs="); if (f[0] == '$' && f[1] == '"') f++; item->option.argDescrip = f; item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; item->option.argInfo |= POPT_ARG_STRING; j--; } else if (j != i) item->argv[j] = item->argv[i]; } if (j != i) { item->argv[j] = NULL; item->argc = j; } /*@=modobserver@*/ /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */ if (!strcmp(entryType, "alias")) rc = poptAddItem(con, item, 0); else if (!strcmp(entryType, "exec")) rc = poptAddItem(con, item, 1); /*@=nullstate@*/ exit: rc = 0; /* XXX for now, always return success */ if (b) free(b); return rc; }
/** * Display help text for an option. * @param fp output file handle * @param columns output display width control * @param opt option(s) * @param translation_domain translation domain */ static void singleOptionHelp(FILE * fp, columns_t columns, const struct poptOption * opt, /*@null@*/ const char * translation_domain) /*@globals fileSystem @*/ /*@modifies fp, fileSystem @*/ { size_t maxLeftCol = columns->cur; size_t indentLength = maxLeftCol + 5; size_t lineLength = columns->max - indentLength; const char * help = D_(translation_domain, opt->descrip); const char * argDescrip = getArgDescrip(opt, translation_domain); /* Display shortName iff printable non-space. */ int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); size_t helpLength; char * defs = NULL; char * left; size_t nb = maxLeftCol + 1; int displaypad = 0; /* Make sure there's more than enough room in target buffer. */ if (opt->longName) nb += strlen(opt->longName); if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1; if (argDescrip) nb += strlen(argDescrip); left = (char*) xmalloc(nb); assert(left); /* XXX can't happen */ if (left == NULL) return; left[0] = '\0'; left[maxLeftCol] = '\0'; #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ if (!(prtshort || prtlong)) goto out; if (prtshort && prtlong) { char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--"; left[0] = '-'; left[1] = opt->shortName; (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName); } else if (prtshort) { left[0] = '-'; left[1] = opt->shortName; left[2] = '\0'; } else if (prtlong) { /* XXX --long always padded for alignment with/without "-X, ". */ char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? "" : (F_ISSET(opt, ONEDASH) ? "-" : "--"); const char *longName = opt->longName; const char *toggle; if (F_ISSET(opt, TOGGLE)) { toggle = "[no]"; if (longName[0] == 'n' && longName[1] == 'o') { longName += sizeof("no") - 1; if (longName[0] == '-') longName++; } } else toggle = ""; (void) stpcpy(stpcpy(stpcpy(stpcpy(left, " "), dash), toggle), longName); } #undef prtlong if (argDescrip) { char * le = left + strlen(left); if (F_ISSET(opt, OPTIONAL)) *le++ = '['; /* Choose type of output */ if (F_ISSET(opt, SHOW_DEFAULT)) { defs = singleOptionDefaultValue(lineLength, opt, translation_domain); if (defs) { char * t = (char*) xmalloc((help ? strlen(help) : 0) + strlen(defs) + sizeof(" ")); assert(t); /* XXX can't happen */ if (t) { char * te = t; if (help) te = stpcpy(te, help); *te++ = ' '; strcpy(te, defs); defs = _free(defs); defs = t; } } } if (opt->argDescrip == NULL) { switch (poptArgType(opt)) { case POPT_ARG_NONE: break; case POPT_ARG_VAL: #ifdef NOTNOW /* XXX pug ugly nerdy output */ { long aLong = opt->val; int ops = F_ISSET(opt, LOGICALOPS); int negate = F_ISSET(opt, NOT); /* Don't bother displaying typical values */ if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) break; *le++ = '['; switch (ops) { case POPT_ARGFLAG_OR: *le++ = '|'; /*@innerbreak@*/ break; case POPT_ARGFLAG_AND: *le++ = '&'; /*@innerbreak@*/ break; case POPT_ARGFLAG_XOR: *le++ = '^'; /*@innerbreak@*/ break; default: /*@innerbreak@*/ break; } *le++ = (opt->longName != NULL ? '=' : ' '); if (negate) *le++ = '~'; /*@-formatconst@*/ le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); /*@=formatconst@*/ *le++ = ']'; } #endif break; case POPT_ARG_INT: case POPT_ARG_SHORT: case POPT_ARG_LONG: case POPT_ARG_LONGLONG: case POPT_ARG_FLOAT: case POPT_ARG_DOUBLE: case POPT_ARG_STRING: *le++ = (opt->longName != NULL ? '=' : ' '); le = stpcpy(le, argDescrip); break; default: break; } } else { char *leo; /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ if (!strchr(" =(", argDescrip[0])) *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' : (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '='); le = stpcpy(leo = le, argDescrip); /* Adjust for (possible) wide characters. */ displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip)); } if (F_ISSET(opt, OPTIONAL)) *le++ = ']'; *le = '\0'; } if (help) POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); else { POPT_fprintf(fp," %s\n", left); goto out; } left = _free(left); if (defs) help = defs; helpLength = strlen(help); while (helpLength > lineLength) { const char * ch; char format[16]; ch = help + lineLength - 1; while (ch > help && !_isspaceptr(ch)) ch = POPT_prev_char(ch); if (ch == help) break; /* give up */ while (ch > (help + 1) && _isspaceptr(ch)) ch = POPT_prev_char (ch); ch = POPT_next_char(ch); /* * XXX strdup is necessary to add NUL terminator so that an unknown * no. of (possible) multi-byte characters can be displayed. */ { char * fmthelp = xstrdup(help); if (fmthelp) { fmthelp[ch - help] = '\0'; sprintf(format, "%%s\n%%%ds", (int) indentLength); /*@-formatconst@*/ POPT_fprintf(fp, format, fmthelp, " "); /*@=formatconst@*/ free(fmthelp); } } help = ch; while (_isspaceptr(help) && *help) help = POPT_next_char(help); helpLength = strlen(help); } if (helpLength) fprintf(fp, "%s\n", help); help = NULL; out: /*@-dependenttrans@*/ defs = _free(defs); /*@=dependenttrans@*/ left = _free(left); }
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; }
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) { const char * se; char quote = '\0'; size_t argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; const char ** argv = (const char**) xmalloc(sizeof(*argv) * argvAlloced); unsigned int argc = 0; size_t ns = strlen(s); char * t = NULL; char * te; int rc = POPT_ERROR_MALLOC; assert(argv); /* XXX can't happen */ if (argv == NULL) return rc; te = t = (char*) xmalloc(ns + 1); assert(te); /* XXX can't happen */ if (te == NULL) { argv = _free(argv); return rc; } *te = '\0'; argv[argc] = te; for (se = s; *se != '\0'; se++) { if (quote == *se) { quote = '\0'; } else if (quote != '\0') { if (*se == '\\') { se++; if (*se == '\0') { rc = POPT_ERROR_BADQUOTE; goto exit; } if (*se != quote) *te++ = '\\'; } *te++ = *se; } else if (_isspaceptr(se)) { if (*argv[argc] != '\0') { *te++ = '\0', argc++; if (argc == argvAlloced) { argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; argv = (const char**) xrealloc(argv, sizeof(*argv) * argvAlloced); assert(argv); /* XXX can't happen */ if (argv == NULL) goto exit; } *te = '\0'; argv[argc] = te; } } else switch (*se) { case '"': case '\'': quote = *se; /*@switchbreak@*/ break; case '\\': se++; if (*se == '\0') { rc = POPT_ERROR_BADQUOTE; goto exit; } /*@fallthrough@*/ default: *te++ = *se; /*@switchbreak@*/ break; } } if (strlen(argv[argc])) { argc++, *te++ = '\0'; } rc = poptDupArgv(argc, argv, argcPtr, argvPtr); exit: t = _free(t); 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)) { size_t nline = 8192; /* XXX configurable? */ char * line = (char*) alloca(nline); char * argstr; char * q; char * x; size_t t; size_t argvlen = 0; size_t maxargvlen = (size_t)480; if (argstrp) *argstrp = NULL; /* | this_is = our_line * p q x */ if (fp == NULL) return POPT_ERROR_NULLARG; argstr = (char*) xmalloc(maxargvlen * sizeof(*argstr)); assert(argstr); /* XXX can't happen */ if (argstr == NULL) return POPT_ERROR_MALLOC; argstr[0] = '\0'; while (fgets(line, (int)nline, fp) != NULL) { char * l = line; size_t nl; /* loop until first non-space char or EOL */ while( *l != '\0' && _isspaceptr(l) ) l++; nl = strlen(l); if (nl >= nline-1) { argstr = _free(argstr); return POPT_ERROR_OVERFLOW; /* XXX line too long */ } if (*l == '\0' || *l == '\n') continue; /* line is empty */ if (*l == '#') continue; /* comment line */ q = l; 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 - l)) + (sizeof(" --")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; argstr = (char*) xrealloc(argstr, maxargvlen); assert(argstr); /* XXX can't happen */ if (argstr == NULL) return POPT_ERROR_MALLOC; } strcat(argstr, " --"); /* XXX stpcpy */ strcat(argstr, l); /* XXX stpcpy */ 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 = l + nl; while (_isspaceptr(--x)) *x = '\0'; /* null out last char if space (including fgets() NL) */ /* rest of line accept */ t = (size_t)(x - l); argvlen += t + (sizeof("' --='")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; argstr = (char*) xrealloc(argstr, maxargvlen); assert(argstr); /* XXX can't happen */ if (argstr == NULL) return POPT_ERROR_MALLOC; } strcat(argstr, " --"); /* XXX stpcpy */ strcat(argstr, l); /* XXX stpcpy */ strcat(argstr, "=\""); /* XXX stpcpy */ strcat(argstr, q); /* XXX stpcpy */ strcat(argstr, "\""); /* XXX stpcpy */ } *argstrp = argstr; return 0; }