📄 popt.c
字号:
/** \ingroup popt * \file popt/popt.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 */#undef MYDEBUG#include "system.h"#if HAVE_FLOAT_H#include <float.h>#endif#include <math.h>#include "findme.h"#include "poptint.h"#ifndef DBL_EPSILON#define DBL_EPSILON 2.2204460492503131e-16#endif#ifdef MYDEBUG/*@unchecked@*/int _popt_debug = 0;#endif#if !defined(HAVE_STRERROR) && !defined(__LCLINT__)static char * strerror(int errno){ extern int sys_nerr; extern char * sys_errlist[]; if ((0 <= errno) && (errno < sys_nerr)) return sys_errlist[errno]; else return POPT_("unknown errno");}#endif#ifdef MYDEBUG/*@unused@*/static void prtcon(const char *msg, poptContext con){ if (msg) fprintf(stderr, "%s", msg); fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", con, con->os, (con->os->nextCharArg ? con->os->nextCharArg : ""), (con->os->nextArg ? con->os->nextArg : ""), con->os->next, (con->os->argv && con->os->argv[con->os->next] ? con->os->argv[con->os->next] : ""));}#endifvoid poptSetExecPath(poptContext con, const char * path, int allowAbsolute){ con->execPath = _free(con->execPath); con->execPath = xstrdup(path); con->execAbsolute = allowAbsolute; /*@-nullstate@*/ /* LCL: con->execPath not NULL */ return; /*@=nullstate@*/}static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) /*@globals internalState@*/ /*@modifies internalState@*/{ if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->arg == NULL) continue; /* XXX program error. */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg;/*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;/*@=branchstate@*/ /* Recurse on included sub-tables. */ invokeCallbacksPRE(con, arg); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && (opt->argInfo & POPT_CBFLAG_PRE)) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)opt->arg; /*@=castfcnptr@*/ /* Perform callback. */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); /*@=noeffectuncon @*/ } }}static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) /*@globals internalState@*/ /*@modifies internalState@*/{ if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->arg == NULL) continue; /* XXX program error. */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg;/*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;/*@=branchstate@*/ /* Recurse on included sub-tables. */ invokeCallbacksPOST(con, arg); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && (opt->argInfo & POPT_CBFLAG_POST)) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)opt->arg; /*@=castfcnptr@*/ /* Perform callback. */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); /*@=noeffectuncon @*/ } }}static void invokeCallbacksOPTION(poptContext con, const struct poptOption * opt, const struct poptOption * myOpt, /*@null@*/ const void * myData, int shorty) /*@globals internalState@*/ /*@modifies internalState@*/{ const struct poptOption * cbopt = NULL; if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg;/*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;/*@=branchstate@*/ /* Recurse on included sub-tables. */ if (opt->arg != NULL) /* XXX program error */ invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { /* Save callback info. */ cbopt = opt; } else if (cbopt != NULL && ((myOpt->shortName && opt->shortName && shorty && myOpt->shortName == opt->shortName) || (myOpt->longName && opt->longName && /*@-nullpass@*/ /* LCL: opt->longName != NULL */ !strcmp(myOpt->longName, opt->longName))) /*@=nullpass@*/ ) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)cbopt->arg; /*@=castfcnptr@*/ const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); /* Perform callback. */ if (cb != NULL) { /* XXX program error */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, con->os->nextArg, cbData); /*@=noeffectuncon @*/ } /* Terminate (unless explcitly continuing). */ if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) return; } }}poptContext poptGetContext(const char * name, int argc, const char ** argv, const struct poptOption * options, int flags){ poptContext con = malloc(sizeof(*con)); if (con == NULL) return NULL; /* XXX can't happen */ memset(con, 0, sizeof(*con)); con->os = con->optionStack; con->os->argc = argc; /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->os->argv = argv; /*@=dependenttrans =assignexpose@*/ con->os->argb = NULL; if (!(flags & POPT_CONTEXT_KEEP_FIRST)) con->os->next = 1; /* skip argv[0] */ con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->options = options; /*@=dependenttrans =assignexpose@*/ con->aliases = NULL; con->numAliases = 0; con->flags = flags; con->execs = NULL; con->numExecs = 0; con->finalArgvAlloced = argc * 2; con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) ); con->execAbsolute = 1; con->arg_strip = NULL; if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) con->flags |= POPT_CONTEXT_POSIXMEHARDER; if (name) { size_t bufsize = strlen(name) + 1; char * t = malloc(bufsize); if (t) { strlcpy(t, name, bufsize); con->appName = t; } } /*@-internalglobs@*/ invokeCallbacksPRE(con, con->options); /*@=internalglobs@*/ return con;}static void cleanOSE(/*@special@*/ struct optionStackEntry *os) /*@uses os @*/ /*@releases os->nextArg, os->argv, os->argb @*/ /*@modifies os @*/{ os->nextArg = _free(os->nextArg); os->argv = _free(os->argv); os->argb = PBM_FREE(os->argb);}/*@-boundswrite@*/void poptResetContext(poptContext con){ int i; if (con == NULL) return; while (con->os > con->optionStack) { cleanOSE(con->os--); } con->os->argb = PBM_FREE(con->os->argb); con->os->currAlias = NULL; con->os->nextCharArg = NULL; con->os->nextArg = NULL; con->os->next = 1; /* skip argv[0] */ con->numLeftovers = 0; con->nextLeftover = 0; con->restLeftover = 0; con->doExec = NULL; if (con->finalArgv != NULL) for (i = 0; i < con->finalArgvCount; i++) { /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ con->finalArgv[i] = _free(con->finalArgv[i]); /*@=unqualifiedtrans@*/ } con->finalArgvCount = 0; con->arg_strip = PBM_FREE(con->arg_strip); /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ return; /*@=nullstate@*/}/*@=boundswrite@*//* Only one of longName, shortName should be set, not both. *//*@-boundswrite@*/static int handleExec(/*@special@*/ poptContext con, /*@null@*/ const char * longName, char shortName) /*@uses con->execs, con->numExecs, con->flags, con->doExec, con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ /*@modifies con @*/{ poptItem item; int i; if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ return 0; for (i = con->numExecs - 1; i >= 0; i--) { item = con->execs + i; if (longName && !(item->option.longName && !strcmp(longName, item->option.longName))) continue; else if (shortName != item->option.shortName) continue; break; } if (i < 0) return 0; if (con->flags & POPT_CONTEXT_NO_EXEC) return 1; if (con->doExec == NULL) { con->doExec = con->execs + i; return 1; } /* We already have an exec to do; remember this option for next time 'round */ if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { con->finalArgvAlloced += 10; con->finalArgv = realloc(con->finalArgv, sizeof(*con->finalArgv) * con->finalArgvAlloced); } i = con->finalArgvCount++; if (con->finalArgv != NULL) /* XXX can't happen */ { size_t bufsize = (longName ? strlen(longName) : 0) + 3; char *s = malloc(bufsize); if (s != NULL) { /* XXX can't happen */ if (longName) snprintf(s, bufsize, "--%s", longName); else snprintf(s, bufsize, "-%c", shortName); con->finalArgv[i] = s; } else con->finalArgv[i] = NULL; } /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ return 1; /*@=nullstate@*/}/*@=boundswrite@*//* Only one of longName, shortName may be set at a time */static int handleAlias(/*@special@*/ poptContext con, /*@null@*/ const char * longName, char shortName, /*@exposed@*/ /*@null@*/ const char * nextCharArg) /*@uses con->aliases, con->numAliases, con->optionStack, con->os, con->os->currAlias, con->os->currAlias->option.longName @*/ /*@modifies con @*/{ poptItem item = con->os->currAlias; int rc; int i; if (item) { if (longName && (item->option.longName && !strcmp(longName, item->option.longName))) return 0; if (shortName && shortName == item->option.shortName) return 0; } if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ return 0; for (i = con->numAliases - 1; i >= 0; i--) { item = con->aliases + i; if (longName && !(item->option.longName && !strcmp(longName, item->option.longName))) continue; else if (shortName != item->option.shortName) continue; break; } if (i < 0) return 0; if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) return POPT_ERROR_OPTSTOODEEP;/*@-boundsread@*/ if (nextCharArg && *nextCharArg) con->os->nextCharArg = nextCharArg;/*@=boundsread@*/ con->os++; con->os->next = 0; con->os->stuffed = 0; con->os->nextArg = NULL; con->os->nextCharArg = NULL; con->os->currAlias = con->aliases + i; rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, &con->os->argc, &con->os->argv); con->os->argb = NULL; return (rc ? rc : 1);}/*@-bounds -boundswrite @*/static int execCommand(poptContext con) /*@globals internalState @*/ /*@modifies internalState @*/{ poptItem item = con->doExec; const char ** argv; int argc = 0; if (item == NULL) /*XXX can't happen*/ return POPT_ERROR_NOARG; if (item->argv == NULL || item->argc < 1 || (!con->execAbsolute && strchr(item->argv[0], '/'))) return POPT_ERROR_NOARG; argv = malloc(sizeof(*argv) * (6 + item->argc + con->numLeftovers + con->finalArgvCount)); if (argv == NULL) return POPT_ERROR_MALLOC; if (!strchr(item->argv[0], '/') && con->execPath != NULL) { size_t bufsize = strlen(con->execPath) + strlen(item->argv[0]) + sizeof "/"; char *s = alloca(bufsize); snprintf(s, bufsize, "%s/%s", con->execPath, item->argv[0]); argv[argc] = s; } else argv[argc] = findProgramPath(item->argv[0]); if (argv[argc++] == NULL) return POPT_ERROR_NOARG; if (item->argc > 1) { memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); argc += (item->argc - 1); } if (con->finalArgv != NULL && con->finalArgvCount > 0) { memcpy(argv + argc, con->finalArgv, sizeof(*argv) * con->finalArgvCount); argc += con->finalArgvCount; } if (con->leftovers != NULL && con->numLeftovers > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -