popt.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787
  1. /** \ingroup popt
  2. * \file popt/popt.c
  3. */
  4. /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
  5. file accompanying popt source distributions, available from
  6. ftp://ftp.rpm.org/pub/rpm/dist */
  7. #undef MYDEBUG
  8. #include "system.h"
  9. #if defined(__LCLINT__)
  10. /*@-declundef -exportheader @*/
  11. extern long long int strtoll(const char *nptr, /*@null@*/ char **endptr,
  12. int base)
  13. /*@modifies *endptr@*/;
  14. /*@=declundef =exportheader @*/
  15. #endif
  16. #ifdef HAVE_FLOAT_H
  17. #include <float.h>
  18. #endif
  19. #include <math.h>
  20. #include "poptint.h"
  21. #ifdef MYDEBUG
  22. /*@unchecked@*/
  23. int _popt_debug = 0;
  24. #endif
  25. /*@unchecked@*/
  26. unsigned int _poptArgMask = POPT_ARG_MASK;
  27. /*@unchecked@*/
  28. unsigned int _poptGroupMask = POPT_GROUP_MASK;
  29. #if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
  30. static char * strerror(int errno)
  31. {
  32. extern int sys_nerr;
  33. extern char * sys_errlist[];
  34. if ((0 <= errno) && (errno < sys_nerr))
  35. return sys_errlist[errno];
  36. else
  37. return POPT_("unknown errno");
  38. }
  39. #endif
  40. #ifdef MYDEBUG
  41. /*@unused@*/
  42. static void prtcon(const char *msg, poptContext con)
  43. {
  44. if (msg) fprintf(stderr, "%s", msg);
  45. fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
  46. con, con->os,
  47. (con->os->nextCharArg ? con->os->nextCharArg : ""),
  48. (con->os->nextArg ? con->os->nextArg : ""),
  49. con->os->next,
  50. (con->os->argv && con->os->argv[con->os->next]
  51. ? con->os->argv[con->os->next] : ""));
  52. }
  53. #endif
  54. void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
  55. {
  56. con->execPath = _free(con->execPath);
  57. con->execPath = xstrdup(path);
  58. con->execAbsolute = allowAbsolute;
  59. return;
  60. }
  61. static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
  62. /*@globals internalState@*/
  63. /*@modifies internalState@*/
  64. {
  65. if (opt != NULL)
  66. for (; opt->longName || opt->shortName || opt->arg; opt++) {
  67. poptArg arg = { .ptr = opt->arg };
  68. if (arg.ptr)
  69. switch (poptArgType(opt)) {
  70. case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
  71. poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
  72. invokeCallbacksPRE(con, arg.opt);
  73. /*@switchbreak@*/ break;
  74. case POPT_ARG_CALLBACK: /* Perform callback. */
  75. if (!CBF_ISSET(opt, PRE))
  76. /*@switchbreak@*/ break;
  77. /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
  78. arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
  79. /*@=noeffectuncon @*/
  80. /*@switchbreak@*/ break;
  81. }
  82. }
  83. }
  84. static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
  85. /*@globals internalState@*/
  86. /*@modifies internalState@*/
  87. {
  88. if (opt != NULL)
  89. for (; opt->longName || opt->shortName || opt->arg; opt++) {
  90. poptArg arg = { .ptr = opt->arg };
  91. if (arg.ptr)
  92. switch (poptArgType(opt)) {
  93. case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
  94. poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
  95. invokeCallbacksPOST(con, arg.opt);
  96. /*@switchbreak@*/ break;
  97. case POPT_ARG_CALLBACK: /* Perform callback. */
  98. if (!CBF_ISSET(opt, POST))
  99. /*@switchbreak@*/ break;
  100. /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
  101. arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
  102. /*@=noeffectuncon @*/
  103. /*@switchbreak@*/ break;
  104. }
  105. }
  106. }
  107. static void invokeCallbacksOPTION(poptContext con,
  108. const struct poptOption * opt,
  109. const struct poptOption * myOpt,
  110. /*@null@*/ const void * myData, int shorty)
  111. /*@globals internalState@*/
  112. /*@modifies internalState@*/
  113. {
  114. const struct poptOption * cbopt = NULL;
  115. poptArg cbarg = { .ptr = NULL };
  116. if (opt != NULL)
  117. for (; opt->longName || opt->shortName || opt->arg; opt++) {
  118. poptArg arg = { .ptr = opt->arg };
  119. switch (poptArgType(opt)) {
  120. case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
  121. poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
  122. if (opt->arg != NULL)
  123. invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty);
  124. /*@switchbreak@*/ break;
  125. case POPT_ARG_CALLBACK: /* Save callback info. */
  126. if (CBF_ISSET(opt, SKIPOPTION))
  127. /*@switchbreak@*/ break;
  128. cbopt = opt;
  129. cbarg.ptr = opt->arg;
  130. /*@switchbreak@*/ break;
  131. default: /* Perform callback on matching option. */
  132. if (cbopt == NULL || cbarg.cb == NULL)
  133. /*@switchbreak@*/ break;
  134. if ((myOpt->shortName && opt->shortName && shorty &&
  135. myOpt->shortName == opt->shortName)
  136. || (myOpt->longName != NULL && opt->longName != NULL &&
  137. !strcmp(myOpt->longName, opt->longName)))
  138. { const void *cbData = (cbopt->descrip ? cbopt->descrip : myData);
  139. /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
  140. cbarg.cb(con, POPT_CALLBACK_REASON_OPTION,
  141. myOpt, con->os->nextArg, cbData);
  142. /*@=noeffectuncon @*/
  143. /* Terminate (unless explcitly continuing). */
  144. if (!CBF_ISSET(cbopt, CONTINUE))
  145. return;
  146. }
  147. /*@switchbreak@*/ break;
  148. }
  149. }
  150. }
  151. poptContext poptGetContext(const char * name, int argc, const char ** argv,
  152. const struct poptOption * options, unsigned int flags)
  153. {
  154. poptContext con = malloc(sizeof(*con));
  155. if (con == NULL) return NULL; /* XXX can't happen */
  156. memset(con, 0, sizeof(*con));
  157. con->os = con->optionStack;
  158. con->os->argc = argc;
  159. /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
  160. con->os->argv = argv;
  161. /*@=dependenttrans =assignexpose@*/
  162. con->os->argb = NULL;
  163. if (!(flags & POPT_CONTEXT_KEEP_FIRST))
  164. con->os->next = 1; /* skip argv[0] */
  165. con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) );
  166. /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
  167. con->options = options;
  168. /*@=dependenttrans =assignexpose@*/
  169. con->aliases = NULL;
  170. con->numAliases = 0;
  171. con->flags = flags;
  172. con->execs = NULL;
  173. con->numExecs = 0;
  174. con->finalArgvAlloced = argc * 2;
  175. con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) );
  176. con->execAbsolute = 1;
  177. con->arg_strip = NULL;
  178. if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
  179. con->flags |= POPT_CONTEXT_POSIXMEHARDER;
  180. if (name)
  181. con->appName = xstrdup(name);
  182. invokeCallbacksPRE(con, con->options);
  183. return con;
  184. }
  185. static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
  186. /*@uses os @*/
  187. /*@releases os->nextArg, os->argv, os->argb @*/
  188. /*@modifies os @*/
  189. {
  190. os->nextArg = _free(os->nextArg);
  191. os->argv = _free(os->argv);
  192. os->argb = PBM_FREE(os->argb);
  193. }
  194. void poptResetContext(poptContext con)
  195. {
  196. int i;
  197. if (con == NULL) return;
  198. while (con->os > con->optionStack) {
  199. cleanOSE(con->os--);
  200. }
  201. con->os->argb = PBM_FREE(con->os->argb);
  202. con->os->currAlias = NULL;
  203. con->os->nextCharArg = NULL;
  204. con->os->nextArg = NULL;
  205. con->os->next = 1; /* skip argv[0] */
  206. con->numLeftovers = 0;
  207. con->nextLeftover = 0;
  208. con->restLeftover = 0;
  209. con->doExec = NULL;
  210. if (con->finalArgv != NULL)
  211. for (i = 0; i < con->finalArgvCount; i++) {
  212. /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
  213. con->finalArgv[i] = _free(con->finalArgv[i]);
  214. /*@=unqualifiedtrans@*/
  215. }
  216. con->finalArgvCount = 0;
  217. con->arg_strip = PBM_FREE(con->arg_strip);
  218. /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */
  219. return;
  220. /*@=nullstate@*/
  221. }
  222. /* Only one of longName, shortName should be set, not both. */
  223. static int handleExec(/*@special@*/ poptContext con,
  224. /*@null@*/ const char * longName, char shortName)
  225. /*@uses con->execs, con->numExecs, con->flags, con->doExec,
  226. con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/
  227. /*@modifies con @*/
  228. {
  229. poptItem item;
  230. int i;
  231. if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */
  232. return 0;
  233. for (i = con->numExecs - 1; i >= 0; i--) {
  234. item = con->execs + i;
  235. if (longName && !(item->option.longName &&
  236. !strcmp(longName, item->option.longName)))
  237. continue;
  238. else if (shortName != item->option.shortName)
  239. continue;
  240. break;
  241. }
  242. if (i < 0) return 0;
  243. if (con->flags & POPT_CONTEXT_NO_EXEC)
  244. return 1;
  245. if (con->doExec == NULL) {
  246. con->doExec = con->execs + i;
  247. return 1;
  248. }
  249. /* We already have an exec to do; remember this option for next
  250. time 'round */
  251. if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
  252. con->finalArgvAlloced += 10;
  253. con->finalArgv = realloc(con->finalArgv,
  254. sizeof(*con->finalArgv) * con->finalArgvAlloced);
  255. }
  256. i = con->finalArgvCount++;
  257. if (con->finalArgv != NULL) /* XXX can't happen */
  258. { char *s = malloc((longName ? strlen(longName) : 0) + sizeof("--"));
  259. if (s != NULL) { /* XXX can't happen */
  260. con->finalArgv[i] = s;
  261. *s++ = '-';
  262. if (longName)
  263. s = stpcpy( stpcpy(s, "-"), longName);
  264. else
  265. *s++ = shortName;
  266. *s = '\0';
  267. } else
  268. con->finalArgv[i] = NULL;
  269. }
  270. return 1;
  271. }
  272. /**
  273. * Compare long option for equality, adjusting for POPT_ARGFLAG_TOGGLE.
  274. * @param opt option
  275. * @param longName arg option
  276. * @param longNameLen arg option length
  277. * @return does long option match?
  278. */
  279. static int
  280. longOptionStrcmp(const struct poptOption * opt,
  281. /*@null@*/ const char * longName, size_t longNameLen)
  282. /*@*/
  283. {
  284. const char * optLongName = opt->longName;
  285. int rc;
  286. if (optLongName == NULL || longName == NULL) /* XXX can't heppen */
  287. return 0;
  288. if (F_ISSET(opt, TOGGLE)) {
  289. if (optLongName[0] == 'n' && optLongName[1] == 'o') {
  290. optLongName += sizeof("no") - 1;
  291. if (optLongName[0] == '-')
  292. optLongName++;
  293. }
  294. if (longName[0] == 'n' && longName[1] == 'o') {
  295. longName += sizeof("no") - 1;
  296. longNameLen -= sizeof("no") - 1;
  297. if (longName[0] == '-') {
  298. longName++;
  299. longNameLen--;
  300. }
  301. }
  302. }
  303. rc = (int)(strlen(optLongName) == longNameLen);
  304. if (rc)
  305. rc = (int)(strncmp(optLongName, longName, longNameLen) == 0);
  306. return rc;
  307. }
  308. /* Only one of longName, shortName may be set at a time */
  309. static int handleAlias(/*@special@*/ poptContext con,
  310. /*@null@*/ const char * longName, size_t longNameLen,
  311. char shortName,
  312. /*@exposed@*/ /*@null@*/ const char * nextArg)
  313. /*@uses con->aliases, con->numAliases, con->optionStack, con->os,
  314. con->os->currAlias, con->os->currAlias->option.longName @*/
  315. /*@modifies con @*/
  316. {
  317. poptItem item = con->os->currAlias;
  318. int rc;
  319. int i;
  320. if (item) {
  321. if (longName && item->option.longName != NULL
  322. && longOptionStrcmp(&item->option, longName, longNameLen))
  323. return 0;
  324. else
  325. if (shortName && shortName == item->option.shortName)
  326. return 0;
  327. }
  328. if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */
  329. return 0;
  330. for (i = con->numAliases - 1; i >= 0; i--) {
  331. item = con->aliases + i;
  332. if (longName) {
  333. if (item->option.longName == NULL)
  334. continue;
  335. if (!longOptionStrcmp(&item->option, longName, longNameLen))
  336. continue;
  337. } else if (shortName != item->option.shortName)
  338. continue;
  339. break;
  340. }
  341. if (i < 0) return 0;
  342. if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
  343. return POPT_ERROR_OPTSTOODEEP;
  344. if (longName == NULL && nextArg != NULL && *nextArg != '\0')
  345. con->os->nextCharArg = nextArg;
  346. con->os++;
  347. con->os->next = 0;
  348. con->os->stuffed = 0;
  349. con->os->nextArg = NULL;
  350. con->os->nextCharArg = NULL;
  351. con->os->currAlias = con->aliases + i;
  352. { const char ** av;
  353. int ac = con->os->currAlias->argc;
  354. /* Append --foo=bar arg to alias argv array (if present). */
  355. if (longName && nextArg != NULL && *nextArg != '\0') {
  356. av = malloc((ac + 1 + 1) * sizeof(*av));
  357. if (av != NULL) { /* XXX won't happen. */
  358. for (i = 0; i < ac; i++) {
  359. av[i] = con->os->currAlias->argv[i];
  360. }
  361. av[ac++] = nextArg;
  362. av[ac] = NULL;
  363. } else /* XXX revert to old popt behavior if malloc fails. */
  364. av = con->os->currAlias->argv;
  365. } else
  366. av = con->os->currAlias->argv;
  367. rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv);
  368. if (av != NULL && av != con->os->currAlias->argv)
  369. free(av);
  370. }
  371. con->os->argb = NULL;
  372. return (rc ? rc : 1);
  373. }
  374. /**
  375. * Return absolute path to executable by searching PATH.
  376. * @param argv0 name of executable
  377. * @return (malloc'd) absolute path to executable (or NULL)
  378. */
  379. static /*@null@*/
  380. const char * findProgramPath(/*@null@*/ const char * argv0)
  381. /*@*/
  382. {
  383. char *path = NULL, *s = NULL, *se;
  384. char *t = NULL;
  385. if (argv0 == NULL) return NULL; /* XXX can't happen */
  386. /* If there is a / in argv[0], it has to be an absolute path. */
  387. /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */
  388. if (strchr(argv0, '/'))
  389. return xstrdup(argv0);
  390. if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL)
  391. return NULL;
  392. /* The return buffer in t is big enough for any path. */
  393. if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL)
  394. for (s = path; s && *s; s = se) {
  395. /* Snip PATH element into [s,se). */
  396. if ((se = strchr(s, ':')))
  397. *se++ = '\0';
  398. /* Append argv0 to PATH element. */
  399. (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0);
  400. /* If file is executable, bingo! */
  401. if (!access(t, X_OK))
  402. break;
  403. }
  404. /* If no executable was found in PATH, return NULL. */
  405. /*@-compdef@*/
  406. if (!(s && *s) && t != NULL)
  407. t = _free(t);
  408. /*@=compdef@*/
  409. /*@-modobserver -observertrans -usedef @*/
  410. path = _free(path);
  411. /*@=modobserver =observertrans =usedef @*/
  412. return t;
  413. }
  414. static int execCommand(poptContext con)
  415. /*@globals internalState @*/
  416. /*@modifies internalState @*/
  417. {
  418. poptItem item = con->doExec;
  419. poptArgv argv = NULL;
  420. int argc = 0;
  421. int rc;
  422. int ec = POPT_ERROR_ERRNO;
  423. if (item == NULL) /*XXX can't happen*/
  424. return POPT_ERROR_NOARG;
  425. if (item->argv == NULL || item->argc < 1 ||
  426. (!con->execAbsolute && strchr(item->argv[0], '/')))
  427. return POPT_ERROR_NOARG;
  428. argv = malloc(sizeof(*argv) *
  429. (6 + item->argc + con->numLeftovers + con->finalArgvCount));
  430. if (argv == NULL) return POPT_ERROR_MALLOC;
  431. if (!strchr(item->argv[0], '/') && con->execPath != NULL) {
  432. char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
  433. if (s)
  434. (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]);
  435. argv[argc] = s;
  436. } else
  437. argv[argc] = findProgramPath(item->argv[0]);
  438. if (argv[argc++] == NULL) {
  439. ec = POPT_ERROR_NOARG;
  440. goto exit;
  441. }
  442. if (item->argc > 1) {
  443. memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1));
  444. argc += (item->argc - 1);
  445. }
  446. if (con->finalArgv != NULL && con->finalArgvCount > 0) {
  447. memcpy(argv + argc, con->finalArgv,
  448. sizeof(*argv) * con->finalArgvCount);
  449. argc += con->finalArgvCount;
  450. }
  451. if (con->leftovers != NULL && con->numLeftovers > 0) {
  452. memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers);
  453. argc += con->numLeftovers;
  454. }
  455. argv[argc] = NULL;
  456. #if defined(hpux) || defined(__hpux)
  457. rc = setresgid(getgid(), getgid(),-1);
  458. if (rc) goto exit;
  459. rc = setresuid(getuid(), getuid(),-1);
  460. if (rc) goto exit;
  461. #else
  462. /*
  463. * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
  464. * XXX sez' Timur Bakeyev <mc@bat.ru>
  465. * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
  466. */
  467. #if defined(HAVE_SETUID)
  468. rc = setgid(getgid());
  469. if (rc) goto exit;
  470. rc = setuid(getuid());
  471. if (rc) goto exit;
  472. #elif defined (HAVE_SETREUID)
  473. rc = setregid(getgid(), getgid());
  474. if (rc) goto exit;
  475. rc = setreuid(getuid(), getuid());
  476. if (rc) goto exit;
  477. #else
  478. ; /* Can't drop privileges */
  479. #endif
  480. #endif
  481. #ifdef MYDEBUG
  482. if (_popt_debug)
  483. { poptArgv avp;
  484. fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
  485. for (avp = argv; *avp; avp++)
  486. fprintf(stderr, " '%s'", *avp);
  487. fprintf(stderr, "\n");
  488. }
  489. #endif
  490. /*@-nullstate@*/
  491. rc = execvp(argv[0], (char *const *)argv);
  492. /*@=nullstate@*/
  493. exit:
  494. if (argv) {
  495. if (argv[0])
  496. free((void *)argv[0]);
  497. free(argv);
  498. }
  499. return ec;
  500. }
  501. /*@observer@*/ /*@null@*/
  502. static const struct poptOption *
  503. findOption(const struct poptOption * opt,
  504. /*@null@*/ const char * longName, size_t longNameLen,
  505. char shortName,
  506. /*@null@*/ /*@out@*/ poptCallbackType * callback,
  507. /*@null@*/ /*@out@*/ const void ** callbackData,
  508. unsigned int argInfo)
  509. /*@modifies *callback, *callbackData */
  510. {
  511. const struct poptOption * cb = NULL;
  512. poptArg cbarg = { .ptr = NULL };
  513. /* This happens when a single - is given */
  514. if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0'))
  515. shortName = '-';
  516. for (; opt->longName || opt->shortName || opt->arg; opt++) {
  517. poptArg arg = { .ptr = opt->arg };
  518. switch (poptArgType(opt)) {
  519. case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
  520. { const struct poptOption * opt2;
  521. poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
  522. if (arg.ptr == NULL) continue; /* XXX program error */
  523. opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback,
  524. callbackData, argInfo);
  525. if (opt2 == NULL) continue;
  526. /* Sub-table data will be inheirited if no data yet. */
  527. /*@-observertrans -dependenttrans @*/
  528. if (callback && *callback
  529. && callbackData && *callbackData == NULL)
  530. *callbackData = opt->descrip;
  531. /*@=observertrans =dependenttrans @*/
  532. return opt2;
  533. } /*@notreached@*/ /*@switchbreak@*/ break;
  534. case POPT_ARG_CALLBACK:
  535. cb = opt;
  536. cbarg.ptr = opt->arg;
  537. continue;
  538. /*@notreached@*/ /*@switchbreak@*/ break;
  539. default:
  540. /*@switchbreak@*/ break;
  541. }
  542. if (longName != NULL && opt->longName != NULL &&
  543. (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) &&
  544. longOptionStrcmp(opt, longName, longNameLen))
  545. {
  546. break;
  547. } else if (shortName && shortName == opt->shortName) {
  548. break;
  549. }
  550. }
  551. if (opt->longName == NULL && !opt->shortName)
  552. return NULL;
  553. /*@-modobserver -mods @*/
  554. if (callback)
  555. *callback = (cb ? cbarg.cb : NULL);
  556. if (callbackData)
  557. /*@-observertrans -dependenttrans @*/
  558. *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL);
  559. /*@=observertrans =dependenttrans @*/
  560. /*@=modobserver =mods @*/
  561. return opt;
  562. }
  563. static const char * findNextArg(/*@special@*/ poptContext con,
  564. unsigned argx, int delete_arg)
  565. /*@uses con->optionStack, con->os,
  566. con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
  567. /*@modifies con @*/
  568. {
  569. struct optionStackEntry * os = con->os;
  570. const char * arg;
  571. do {
  572. int i;
  573. arg = NULL;
  574. while (os->next == os->argc && os > con->optionStack) os--;
  575. if (os->next == os->argc && os == con->optionStack) break;
  576. if (os->argv != NULL)
  577. for (i = os->next; i < os->argc; i++) {
  578. /*@-sizeoftype@*/
  579. if (os->argb && PBM_ISSET(i, os->argb))
  580. /*@innercontinue@*/ continue;
  581. if (*os->argv[i] == '-')
  582. /*@innercontinue@*/ continue;
  583. if (--argx > 0)
  584. /*@innercontinue@*/ continue;
  585. arg = os->argv[i];
  586. if (delete_arg) {
  587. if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
  588. if (os->argb != NULL) /* XXX can't happen */
  589. PBM_SET(i, os->argb);
  590. }
  591. /*@innerbreak@*/ break;
  592. /*@=sizeoftype@*/
  593. }
  594. if (os > con->optionStack) os--;
  595. } while (arg == NULL);
  596. return arg;
  597. }
  598. static /*@only@*/ /*@null@*/ const char *
  599. expandNextArg(/*@special@*/ poptContext con, const char * s)
  600. /*@uses con->optionStack, con->os,
  601. con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
  602. /*@modifies con @*/
  603. {
  604. const char * a = NULL;
  605. char *t, *te;
  606. size_t tn = strlen(s) + 1;
  607. char c;
  608. te = t = malloc(tn);
  609. if (t == NULL) return NULL; /* XXX can't happen */
  610. *t = '\0';
  611. while ((c = *s++) != '\0') {
  612. switch (c) {
  613. #if 0 /* XXX can't do this */
  614. case '\\': /* escape */
  615. c = *s++;
  616. /*@switchbreak@*/ break;
  617. #endif
  618. case '!':
  619. if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
  620. /*@switchbreak@*/ break;
  621. /* XXX Make sure that findNextArg deletes only next arg. */
  622. if (a == NULL) {
  623. if ((a = findNextArg(con, 1U, 1)) == NULL)
  624. /*@switchbreak@*/ break;
  625. }
  626. s += sizeof("#:+") - 1;
  627. tn += strlen(a);
  628. { size_t pos = (size_t) (te - t);
  629. if ((t = realloc(t, tn)) == NULL) /* XXX can't happen */
  630. return NULL;
  631. te = stpcpy(t + pos, a);
  632. }
  633. continue;
  634. /*@notreached@*/ /*@switchbreak@*/ break;
  635. default:
  636. /*@switchbreak@*/ break;
  637. }
  638. *te++ = c;
  639. }
  640. *te++ = '\0';
  641. /* If the new string is longer than needed, shorten. */
  642. if ((t + tn) > te) {
  643. /*@-usereleased@*/ /* XXX splint can't follow the pointers. */
  644. if ((te = realloc(t, (size_t)(te - t))) == NULL)
  645. free(t);
  646. t = te;
  647. /*@=usereleased@*/
  648. }
  649. return t;
  650. }
  651. static void poptStripArg(/*@special@*/ poptContext con, int which)
  652. /*@uses con->optionStack @*/
  653. /*@defines con->arg_strip @*/
  654. /*@modifies con @*/
  655. {
  656. /*@-compdef -sizeoftype -usedef @*/
  657. if (con->arg_strip == NULL)
  658. con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
  659. if (con->arg_strip != NULL) /* XXX can't happen */
  660. PBM_SET(which, con->arg_strip);
  661. return;
  662. /*@=compdef =sizeoftype =usedef @*/
  663. }
  664. /*@unchecked@*/
  665. unsigned int _poptBitsN = _POPT_BITS_N;
  666. /*@unchecked@*/
  667. unsigned int _poptBitsM = _POPT_BITS_M;
  668. /*@unchecked@*/
  669. unsigned int _poptBitsK = _POPT_BITS_K;
  670. /*@-sizeoftype@*/
  671. static int _poptBitsNew(/*@null@*/ poptBits *bitsp)
  672. /*@globals _poptBitsN, _poptBitsM, _poptBitsK @*/
  673. /*@modifies *bitsp, _poptBitsN, _poptBitsM, _poptBitsK @*/
  674. {
  675. if (bitsp == NULL)
  676. return POPT_ERROR_NULLARG;
  677. /* XXX handle negated initialization. */
  678. if (*bitsp == NULL) {
  679. if (_poptBitsN == 0) {
  680. _poptBitsN = _POPT_BITS_N;
  681. _poptBitsM = _POPT_BITS_M;
  682. }
  683. if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2;
  684. if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K;
  685. *bitsp = PBM_ALLOC(_poptBitsM-1);
  686. }
  687. /*@-nullstate@*/
  688. return 0;
  689. /*@=nullstate@*/
  690. }
  691. int poptBitsAdd(poptBits bits, const char * s)
  692. {
  693. size_t ns = (s ? strlen(s) : 0);
  694. uint32_t h0 = 0;
  695. uint32_t h1 = 0;
  696. if (bits == NULL || ns == 0)
  697. return POPT_ERROR_NULLARG;
  698. poptJlu32lpair(s, ns, &h0, &h1);
  699. for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
  700. uint32_t h = h0 + ns * h1;
  701. uint32_t ix = (h % _poptBitsM);
  702. PBM_SET(ix, bits);
  703. }
  704. return 0;
  705. }
  706. int poptBitsChk(poptBits bits, const char * s)
  707. {
  708. size_t ns = (s ? strlen(s) : 0);
  709. uint32_t h0 = 0;
  710. uint32_t h1 = 0;
  711. int rc = 1;
  712. if (bits == NULL || ns == 0)
  713. return POPT_ERROR_NULLARG;
  714. poptJlu32lpair(s, ns, &h0, &h1);
  715. for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
  716. uint32_t h = h0 + ns * h1;
  717. uint32_t ix = (h % _poptBitsM);
  718. if (PBM_ISSET(ix, bits))
  719. continue;
  720. rc = 0;
  721. break;
  722. }
  723. return rc;
  724. }
  725. int poptBitsClr(poptBits bits)
  726. {
  727. static size_t nbw = (__PBM_NBITS/8);
  728. size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
  729. if (bits == NULL)
  730. return POPT_ERROR_NULLARG;
  731. memset(bits, 0, nw * nbw);
  732. return 0;
  733. }
  734. int poptBitsDel(poptBits bits, const char * s)
  735. {
  736. size_t ns = (s ? strlen(s) : 0);
  737. uint32_t h0 = 0;
  738. uint32_t h1 = 0;
  739. if (bits == NULL || ns == 0)
  740. return POPT_ERROR_NULLARG;
  741. poptJlu32lpair(s, ns, &h0, &h1);
  742. for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
  743. uint32_t h = h0 + ns * h1;
  744. uint32_t ix = (h % _poptBitsM);
  745. PBM_CLR(ix, bits);
  746. }
  747. return 0;
  748. }
  749. int poptBitsIntersect(poptBits *ap, const poptBits b)
  750. {
  751. __pbm_bits *abits;
  752. __pbm_bits *bbits;
  753. __pbm_bits rc = 0;
  754. size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
  755. size_t i;
  756. if (ap == NULL || b == NULL || _poptBitsNew(ap))
  757. return POPT_ERROR_NULLARG;
  758. abits = __PBM_BITS(*ap);
  759. bbits = __PBM_BITS(b);
  760. for (i = 0; i < nw; i++) {
  761. abits[i] &= bbits[i];
  762. rc |= abits[i];
  763. }
  764. return (rc ? 1 : 0);
  765. }
  766. int poptBitsUnion(poptBits *ap, const poptBits b)
  767. {
  768. __pbm_bits *abits;
  769. __pbm_bits *bbits;
  770. __pbm_bits rc = 0;
  771. size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
  772. size_t i;
  773. if (ap == NULL || b == NULL || _poptBitsNew(ap))
  774. return POPT_ERROR_NULLARG;
  775. abits = __PBM_BITS(*ap);
  776. bbits = __PBM_BITS(b);
  777. for (i = 0; i < nw; i++) {
  778. abits[i] |= bbits[i];
  779. rc |= abits[i];
  780. }
  781. return (rc ? 1 : 0);
  782. }
  783. int poptBitsArgs(poptContext con, poptBits *ap)
  784. {
  785. const char ** av;
  786. int rc = 0;
  787. if (con == NULL || ap == NULL || _poptBitsNew(ap) ||
  788. con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
  789. return POPT_ERROR_NULLARG;
  790. /* some apps like [like RPM ;-) ] need this NULL terminated */
  791. con->leftovers[con->numLeftovers] = NULL;
  792. for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) {
  793. if ((rc = poptBitsAdd(*ap, *av)) != 0)
  794. break;
  795. }
  796. /*@-nullstate@*/
  797. return rc;
  798. /*@=nullstate@*/
  799. }
  800. int poptSaveBits(poptBits * bitsp,
  801. /*@unused@*/ UNUSED(unsigned int argInfo), const char * s)
  802. {
  803. char *tbuf = NULL;
  804. char *t, *te;
  805. int rc = 0;
  806. if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp))
  807. return POPT_ERROR_NULLARG;
  808. /* Parse comma separated attributes. */
  809. te = tbuf = xstrdup(s);
  810. while ((t = te) != NULL && *t) {
  811. while (*te != '\0' && *te != ',')
  812. te++;
  813. if (*te != '\0')
  814. *te++ = '\0';
  815. /* XXX Ignore empty strings. */
  816. if (*t == '\0')
  817. continue;
  818. /* XXX Permit negated attributes. caveat emptor: false negatives. */
  819. if (*t == '!') {
  820. t++;
  821. if ((rc = poptBitsChk(*bitsp, t)) > 0)
  822. rc = poptBitsDel(*bitsp, t);
  823. } else
  824. rc = poptBitsAdd(*bitsp, t);
  825. if (rc)
  826. break;
  827. }
  828. tbuf = _free(tbuf);
  829. return rc;
  830. }
  831. /*@=sizeoftype@*/
  832. int poptSaveString(const char *** argvp,
  833. /*@unused@*/ UNUSED(unsigned int argInfo), const char * val)
  834. {
  835. int argc = 0;
  836. if (argvp == NULL || val == NULL)
  837. return POPT_ERROR_NULLARG;
  838. /* XXX likely needs an upper bound on argc. */
  839. if (*argvp != NULL)
  840. while ((*argvp)[argc] != NULL)
  841. argc++;
  842. /*@-unqualifiedtrans -nullstate@*/ /* XXX no annotation for (*argvp) */
  843. if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) {
  844. (*argvp)[argc++] = xstrdup(val);
  845. (*argvp)[argc ] = NULL;
  846. }
  847. return 0;
  848. /*@=unqualifiedtrans =nullstate@*/
  849. }
  850. /*@unchecked@*/
  851. static unsigned int seed = 0;
  852. int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong)
  853. {
  854. if (arg == NULL
  855. #ifdef NOTYET
  856. /* XXX Check alignment, may fail on funky platforms. */
  857. || (((unsigned long long)arg) & (sizeof(*arg)-1))
  858. #endif
  859. )
  860. return POPT_ERROR_NULLARG;
  861. if (aLongLong != 0 && LF_ISSET(RANDOM)) {
  862. #if defined(HAVE_SRANDOM)
  863. if (!seed) {
  864. srandom((unsigned)getpid());
  865. srandom((unsigned)random());
  866. }
  867. aLongLong = (long long)(random() % (aLongLong > 0 ? aLongLong : -aLongLong));
  868. aLongLong++;
  869. #else
  870. /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
  871. return POPT_ERROR_BADOPERATION;
  872. #endif
  873. }
  874. if (LF_ISSET(NOT))
  875. aLongLong = ~aLongLong;
  876. switch (LF_ISSET(LOGICALOPS)) {
  877. case 0:
  878. *arg = aLongLong;
  879. break;
  880. case POPT_ARGFLAG_OR:
  881. *(unsigned long long *)arg |= (unsigned long long)aLongLong;
  882. break;
  883. case POPT_ARGFLAG_AND:
  884. *(unsigned long long *)arg &= (unsigned long long)aLongLong;
  885. break;
  886. case POPT_ARGFLAG_XOR:
  887. *(unsigned long long *)arg ^= (unsigned long long)aLongLong;
  888. break;
  889. default:
  890. return POPT_ERROR_BADOPERATION;
  891. /*@notreached@*/ break;
  892. }
  893. return 0;
  894. }
  895. int poptSaveLong(long * arg, unsigned int argInfo, long aLong)
  896. {
  897. /* XXX Check alignment, may fail on funky platforms. */
  898. if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
  899. return POPT_ERROR_NULLARG;
  900. if (aLong != 0 && LF_ISSET(RANDOM)) {
  901. #if defined(HAVE_SRANDOM)
  902. if (!seed) {
  903. srandom((unsigned)getpid());
  904. srandom((unsigned)random());
  905. }
  906. aLong = random() % (aLong > 0 ? aLong : -aLong);
  907. aLong++;
  908. #else
  909. /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
  910. return POPT_ERROR_BADOPERATION;
  911. #endif
  912. }
  913. if (LF_ISSET(NOT))
  914. aLong = ~aLong;
  915. switch (LF_ISSET(LOGICALOPS)) {
  916. case 0: *arg = aLong; break;
  917. case POPT_ARGFLAG_OR: *(unsigned long *)arg |= (unsigned long)aLong; break;
  918. case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break;
  919. case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break;
  920. default:
  921. return POPT_ERROR_BADOPERATION;
  922. /*@notreached@*/ break;
  923. }
  924. return 0;
  925. }
  926. int poptSaveInt(/*@null@*/ int * arg, unsigned int argInfo, long aLong)
  927. {
  928. /* XXX Check alignment, may fail on funky platforms. */
  929. if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
  930. return POPT_ERROR_NULLARG;
  931. if (aLong != 0 && LF_ISSET(RANDOM)) {
  932. #if defined(HAVE_SRANDOM)
  933. if (!seed) {
  934. srandom((unsigned)getpid());
  935. srandom((unsigned)random());
  936. }
  937. aLong = random() % (aLong > 0 ? aLong : -aLong);
  938. aLong++;
  939. #else
  940. /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
  941. return POPT_ERROR_BADOPERATION;
  942. #endif
  943. }
  944. if (LF_ISSET(NOT))
  945. aLong = ~aLong;
  946. switch (LF_ISSET(LOGICALOPS)) {
  947. case 0: *arg = (int) aLong; break;
  948. case POPT_ARGFLAG_OR: *(unsigned int *)arg |= (unsigned int) aLong; break;
  949. case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break;
  950. case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break;
  951. default:
  952. return POPT_ERROR_BADOPERATION;
  953. /*@notreached@*/ break;
  954. }
  955. return 0;
  956. }
  957. int poptSaveShort(/*@null@*/ short * arg, unsigned int argInfo, long aLong)
  958. {
  959. /* XXX Check alignment, may fail on funky platforms. */
  960. if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
  961. return POPT_ERROR_NULLARG;
  962. if (aLong != 0 && LF_ISSET(RANDOM)) {
  963. #if defined(HAVE_SRANDOM)
  964. if (!seed) {
  965. srandom((unsigned)getpid());
  966. srandom((unsigned)random());
  967. }
  968. aLong = random() % (aLong > 0 ? aLong : -aLong);
  969. aLong++;
  970. #else
  971. /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
  972. return POPT_ERROR_BADOPERATION;
  973. #endif
  974. }
  975. if (LF_ISSET(NOT))
  976. aLong = ~aLong;
  977. switch (LF_ISSET(LOGICALOPS)) {
  978. case 0: *arg = (short) aLong;
  979. break;
  980. case POPT_ARGFLAG_OR: *(unsigned short *)arg |= (unsigned short) aLong;
  981. break;
  982. case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong;
  983. break;
  984. case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong;
  985. break;
  986. default: return POPT_ERROR_BADOPERATION;
  987. /*@notreached@*/ break;
  988. }
  989. return 0;
  990. }
  991. /**
  992. * Return argInfo field, handling POPT_ARGFLAG_TOGGLE overrides.
  993. * @param con context
  994. * @param opt option
  995. * @return argInfo
  996. */
  997. static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt)
  998. /*@*/
  999. {
  1000. unsigned int argInfo = opt->argInfo;
  1001. if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL)
  1002. if (LF_ISSET(TOGGLE)) {
  1003. const char * longName = con->os->argv[con->os->next-1];
  1004. while (*longName == '-') longName++;
  1005. /* XXX almost good enough but consider --[no]nofoo corner cases. */
  1006. if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1])
  1007. {
  1008. if (!LF_ISSET(XOR)) { /* XXX dont toggle with XOR */
  1009. /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */
  1010. if (LF_ISSET(LOGICALOPS))
  1011. argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND);
  1012. argInfo ^= POPT_ARGFLAG_NOT;
  1013. }
  1014. }
  1015. }
  1016. return argInfo;
  1017. }
  1018. /**
  1019. * Parse an integer expression.
  1020. * @retval *llp integer expression value
  1021. * @param argInfo integer expression type
  1022. * @param val integer expression string
  1023. * @return 0 on success, otherwise POPT_* error.
  1024. */
  1025. static int poptParseInteger(long long * llp,
  1026. /*@unused@*/ UNUSED(unsigned int argInfo),
  1027. /*@null@*/ const char * val)
  1028. /*@modifies *llp @*/
  1029. {
  1030. if (val) {
  1031. char *end = NULL;
  1032. *llp = strtoll(val, &end, 0);
  1033. /* XXX parse scaling suffixes here. */
  1034. if (!(end && *end == '\0'))
  1035. return POPT_ERROR_BADNUMBER;
  1036. } else
  1037. *llp = 0;
  1038. return 0;
  1039. }
  1040. /**
  1041. * Save the option argument through the (*opt->arg) pointer.
  1042. * @param con context
  1043. * @param opt option
  1044. * @return 0 on success, otherwise POPT_* error.
  1045. */
  1046. static int poptSaveArg(poptContext con, const struct poptOption * opt)
  1047. /*@globals fileSystem, internalState @*/
  1048. /*@modifies con, fileSystem, internalState @*/
  1049. {
  1050. poptArg arg = { .ptr = opt->arg };
  1051. int rc = 0; /* assume success */
  1052. switch (poptArgType(opt)) {
  1053. case POPT_ARG_BITSET:
  1054. /* XXX memory leak, application is responsible for free. */
  1055. rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg);
  1056. /*@switchbreak@*/ break;
  1057. case POPT_ARG_ARGV:
  1058. /* XXX memory leak, application is responsible for free. */
  1059. rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg);
  1060. /*@switchbreak@*/ break;
  1061. case POPT_ARG_STRING:
  1062. /* XXX memory leak, application is responsible for free. */
  1063. arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL;
  1064. /*@switchbreak@*/ break;
  1065. case POPT_ARG_INT:
  1066. case POPT_ARG_SHORT:
  1067. case POPT_ARG_LONG:
  1068. case POPT_ARG_LONGLONG:
  1069. { unsigned int argInfo = poptArgInfo(con, opt);
  1070. long long aNUM = 0;
  1071. if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0)
  1072. break;
  1073. switch (poptArgType(opt)) {
  1074. case POPT_ARG_LONGLONG:
  1075. /* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */
  1076. #if !defined(LLONG_MAX)
  1077. # define LLONG_MAX 9223372036854775807LL
  1078. # define LLONG_MIN (-LLONG_MAX - 1LL)
  1079. #endif
  1080. rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX)
  1081. ? poptSaveLongLong(arg.longlongp, argInfo, aNUM)
  1082. : POPT_ERROR_OVERFLOW;
  1083. /*@innerbreak@*/ break;
  1084. case POPT_ARG_LONG:
  1085. rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX)
  1086. ? poptSaveLong(arg.longp, argInfo, (long)aNUM)
  1087. : POPT_ERROR_OVERFLOW;
  1088. /*@innerbreak@*/ break;
  1089. case POPT_ARG_INT:
  1090. rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX)
  1091. ? poptSaveInt(arg.intp, argInfo, (long)aNUM)
  1092. : POPT_ERROR_OVERFLOW;
  1093. /*@innerbreak@*/ break;
  1094. case POPT_ARG_SHORT:
  1095. rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX)
  1096. ? poptSaveShort(arg.shortp, argInfo, (long)aNUM)
  1097. : POPT_ERROR_OVERFLOW;
  1098. /*@innerbreak@*/ break;
  1099. }
  1100. } /*@switchbreak@*/ break;
  1101. case POPT_ARG_FLOAT:
  1102. case POPT_ARG_DOUBLE:
  1103. { char *end = NULL;
  1104. double aDouble = 0.0;
  1105. if (con->os->nextArg) {
  1106. /*@-mods@*/
  1107. int saveerrno = errno;
  1108. errno = 0;
  1109. aDouble = strtod(con->os->nextArg, &end);
  1110. if (errno == ERANGE) {
  1111. rc = POPT_ERROR_OVERFLOW;
  1112. break;
  1113. }
  1114. errno = saveerrno;
  1115. /*@=mods@*/
  1116. if (*end != '\0') {
  1117. rc = POPT_ERROR_BADNUMBER;
  1118. break;
  1119. }
  1120. }
  1121. switch (poptArgType(opt)) {
  1122. case POPT_ARG_DOUBLE:
  1123. arg.doublep[0] = aDouble;
  1124. /*@innerbreak@*/ break;
  1125. case POPT_ARG_FLOAT:
  1126. #if !defined(DBL_EPSILON) && !defined(__LCLINT__)
  1127. #define DBL_EPSILON 2.2204460492503131e-16
  1128. #endif
  1129. #define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
  1130. if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON
  1131. || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
  1132. rc = POPT_ERROR_OVERFLOW;
  1133. else
  1134. arg.floatp[0] = (float) aDouble;
  1135. /*@innerbreak@*/ break;
  1136. }
  1137. } /*@switchbreak@*/ break;
  1138. case POPT_ARG_MAINCALL:
  1139. /*@-assignexpose -type@*/
  1140. con->maincall = opt->arg;
  1141. /*@=assignexpose =type@*/
  1142. /*@switchbreak@*/ break;
  1143. default:
  1144. fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"),
  1145. poptArgType(opt));
  1146. exit(EXIT_FAILURE);
  1147. /*@notreached@*/ /*@switchbreak@*/ break;
  1148. }
  1149. return rc;
  1150. }
  1151. /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
  1152. int poptGetNextOpt(poptContext con)
  1153. {
  1154. const struct poptOption * opt = NULL;
  1155. int done = 0;
  1156. if (con == NULL)
  1157. return -1;
  1158. while (!done) {
  1159. const char * origOptString = NULL;
  1160. poptCallbackType cb = NULL;
  1161. const void * cbData = NULL;
  1162. const char * longArg = NULL;
  1163. int canstrip = 0;
  1164. int shorty = 0;
  1165. while (!con->os->nextCharArg && con->os->next == con->os->argc
  1166. && con->os > con->optionStack) {
  1167. cleanOSE(con->os--);
  1168. }
  1169. if (!con->os->nextCharArg && con->os->next == con->os->argc) {
  1170. invokeCallbacksPOST(con, con->options);
  1171. if (con->maincall) {
  1172. /*@-noeffectuncon @*/
  1173. (void) (*con->maincall) (con->finalArgvCount, con->finalArgv);
  1174. /*@=noeffectuncon @*/
  1175. return -1;
  1176. }
  1177. if (con->doExec) return execCommand(con);
  1178. return -1;
  1179. }
  1180. /* Process next long option */
  1181. if (!con->os->nextCharArg) {
  1182. const char * optString;
  1183. size_t optStringLen;
  1184. int thisopt;
  1185. /*@-sizeoftype@*/
  1186. if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
  1187. con->os->next++;
  1188. continue;
  1189. }
  1190. /*@=sizeoftype@*/
  1191. thisopt = con->os->next;
  1192. if (con->os->argv != NULL) /* XXX can't happen */
  1193. origOptString = con->os->argv[con->os->next++];
  1194. if (origOptString == NULL) /* XXX can't happen */
  1195. return POPT_ERROR_BADOPT;
  1196. if (con->restLeftover || *origOptString != '-' ||
  1197. (*origOptString == '-' && origOptString[1] == '\0'))
  1198. {
  1199. if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
  1200. con->restLeftover = 1;
  1201. if (con->flags & POPT_CONTEXT_ARG_OPTS) {
  1202. con->os->nextArg = xstrdup(origOptString);
  1203. return 0;
  1204. }
  1205. if (con->leftovers != NULL) /* XXX can't happen */
  1206. con->leftovers[con->numLeftovers++] = origOptString;
  1207. continue;
  1208. }
  1209. /* Make a copy we can hack at */
  1210. optString = origOptString;
  1211. if (optString[0] == '\0')
  1212. return POPT_ERROR_BADOPT;
  1213. if (optString[1] == '-' && !optString[2]) {
  1214. con->restLeftover = 1;
  1215. continue;
  1216. } else {
  1217. const char *oe;
  1218. unsigned int argInfo = 0;
  1219. optString++;
  1220. if (*optString == '-')
  1221. optString++;
  1222. else
  1223. argInfo |= POPT_ARGFLAG_ONEDASH;
  1224. /* Check for "--long=arg" option. */
  1225. for (oe = optString; *oe && *oe != '='; oe++)
  1226. {};
  1227. optStringLen = (size_t)(oe - optString);
  1228. if (*oe == '=')
  1229. longArg = oe + 1;
  1230. /* XXX aliases with arg substitution need "--alias=arg" */
  1231. if (handleAlias(con, optString, optStringLen, '\0', longArg)) {
  1232. longArg = NULL;
  1233. continue;
  1234. }
  1235. if (handleExec(con, optString, '\0'))
  1236. continue;
  1237. opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData,
  1238. argInfo);
  1239. if (!opt && !LF_ISSET(ONEDASH))
  1240. return POPT_ERROR_BADOPT;
  1241. }
  1242. if (!opt) {
  1243. con->os->nextCharArg = origOptString + 1;
  1244. longArg = NULL;
  1245. } else {
  1246. if (con->os == con->optionStack && F_ISSET(opt, STRIP))
  1247. {
  1248. canstrip = 1;
  1249. poptStripArg(con, thisopt);
  1250. }
  1251. shorty = 0;
  1252. }
  1253. }
  1254. /* Process next short option */
  1255. if (con->os->nextCharArg) {
  1256. const char * nextCharArg = con->os->nextCharArg;
  1257. con->os->nextCharArg = NULL;
  1258. if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1))
  1259. continue;
  1260. if (handleExec(con, NULL, *nextCharArg)) {
  1261. /* Restore rest of short options for further processing */
  1262. nextCharArg++;
  1263. if (*nextCharArg != '\0')
  1264. con->os->nextCharArg = nextCharArg;
  1265. continue;
  1266. }
  1267. opt = findOption(con->options, NULL, 0, *nextCharArg, &cb,
  1268. &cbData, 0);
  1269. if (!opt)
  1270. return POPT_ERROR_BADOPT;
  1271. shorty = 1;
  1272. nextCharArg++;
  1273. if (*nextCharArg != '\0')
  1274. con->os->nextCharArg = nextCharArg + (int)(*nextCharArg == '=');
  1275. }
  1276. if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */
  1277. if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) {
  1278. unsigned int argInfo = poptArgInfo(con, opt);
  1279. if (poptSaveInt((int *)opt->arg, argInfo, 1L))
  1280. return POPT_ERROR_BADOPERATION;
  1281. } else if (poptArgType(opt) == POPT_ARG_VAL) {
  1282. if (opt->arg) {
  1283. unsigned int argInfo = poptArgInfo(con, opt);
  1284. if (poptSaveInt((int *)opt->arg, argInfo, (long)opt->val))
  1285. return POPT_ERROR_BADOPERATION;
  1286. }
  1287. } else if (poptArgType(opt) != POPT_ARG_NONE) {
  1288. int rc;
  1289. con->os->nextArg = _free(con->os->nextArg);
  1290. if (longArg) {
  1291. longArg = expandNextArg(con, longArg);
  1292. con->os->nextArg = (char *) longArg;
  1293. } else if (con->os->nextCharArg) {
  1294. longArg = expandNextArg(con, con->os->nextCharArg);
  1295. con->os->nextArg = (char *) longArg;
  1296. con->os->nextCharArg = NULL;
  1297. } else {
  1298. while (con->os->next == con->os->argc &&
  1299. con->os > con->optionStack)
  1300. {
  1301. cleanOSE(con->os--);
  1302. }
  1303. if (con->os->next == con->os->argc) {
  1304. if (!F_ISSET(opt, OPTIONAL))
  1305. return POPT_ERROR_NOARG;
  1306. con->os->nextArg = NULL;
  1307. } else {
  1308. /*
  1309. * Make sure this isn't part of a short arg or the
  1310. * result of an alias expansion.
  1311. */
  1312. if (con->os == con->optionStack
  1313. && F_ISSET(opt, STRIP) && canstrip)
  1314. {
  1315. poptStripArg(con, con->os->next);
  1316. }
  1317. if (con->os->argv != NULL) { /* XXX can't happen */
  1318. if (F_ISSET(opt, OPTIONAL) &&
  1319. con->os->argv[con->os->next][0] == '-') {
  1320. con->os->nextArg = NULL;
  1321. } else {
  1322. /* XXX watchout: subtle side-effects live here. */
  1323. longArg = con->os->argv[con->os->next++];
  1324. longArg = expandNextArg(con, longArg);
  1325. con->os->nextArg = (char *) longArg;
  1326. }
  1327. }
  1328. }
  1329. }
  1330. longArg = NULL;
  1331. /* Save the option argument through a (*opt->arg) pointer. */
  1332. if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0)
  1333. return rc;
  1334. }
  1335. if (cb)
  1336. invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
  1337. else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL))
  1338. done = 1;
  1339. if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
  1340. con->finalArgvAlloced += 10;
  1341. con->finalArgv = realloc(con->finalArgv,
  1342. sizeof(*con->finalArgv) * con->finalArgvAlloced);
  1343. }
  1344. if (con->finalArgv != NULL)
  1345. { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--"));
  1346. if (s != NULL) { /* XXX can't happen */
  1347. con->finalArgv[con->finalArgvCount++] = s;
  1348. *s++ = '-';
  1349. if (opt->longName) {
  1350. if (!F_ISSET(opt, ONEDASH))
  1351. *s++ = '-';
  1352. s = stpcpy(s, opt->longName);
  1353. } else {
  1354. *s++ = opt->shortName;
  1355. *s = '\0';
  1356. }
  1357. } else
  1358. con->finalArgv[con->finalArgvCount++] = NULL;
  1359. }
  1360. if (opt->arg && poptArgType(opt) == POPT_ARG_NONE)
  1361. /*@-ifempty@*/ ; /*@=ifempty@*/
  1362. else if (poptArgType(opt) == POPT_ARG_VAL)
  1363. /*@-ifempty@*/ ; /*@=ifempty@*/
  1364. else if (poptArgType(opt) != POPT_ARG_NONE) {
  1365. if (con->finalArgv != NULL && con->os->nextArg != NULL)
  1366. con->finalArgv[con->finalArgvCount++] =
  1367. xstrdup(con->os->nextArg);
  1368. }
  1369. }
  1370. return (opt ? opt->val : -1); /* XXX can't happen */
  1371. }
  1372. char * poptGetOptArg(poptContext con)
  1373. {
  1374. char * ret = NULL;
  1375. if (con) {
  1376. ret = con->os->nextArg;
  1377. con->os->nextArg = NULL;
  1378. }
  1379. return ret;
  1380. }
  1381. const char * poptGetArg(poptContext con)
  1382. {
  1383. const char * ret = NULL;
  1384. if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
  1385. ret = con->leftovers[con->nextLeftover++];
  1386. return ret;
  1387. }
  1388. const char * poptPeekArg(poptContext con)
  1389. {
  1390. const char * ret = NULL;
  1391. if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
  1392. ret = con->leftovers[con->nextLeftover];
  1393. return ret;
  1394. }
  1395. const char ** poptGetArgs(poptContext con)
  1396. {
  1397. if (con == NULL ||
  1398. con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
  1399. return NULL;
  1400. /* some apps like [like RPM ;-) ] need this NULL terminated */
  1401. con->leftovers[con->numLeftovers] = NULL;
  1402. /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
  1403. return (con->leftovers + con->nextLeftover);
  1404. /*@=nullret =nullstate @*/
  1405. }
  1406. static /*@null@*/
  1407. poptItem poptFreeItems(/*@only@*/ /*@null@*/ poptItem items, int nitems)
  1408. /*@modifies items @*/
  1409. {
  1410. if (items != NULL) {
  1411. poptItem item = items;
  1412. while (--nitems >= 0) {
  1413. /*@-modobserver -observertrans -dependenttrans@*/
  1414. item->option.longName = _free(item->option.longName);
  1415. item->option.descrip = _free(item->option.descrip);
  1416. item->option.argDescrip = _free(item->option.argDescrip);
  1417. /*@=modobserver =observertrans =dependenttrans@*/
  1418. item->argv = _free(item->argv);
  1419. item++;
  1420. }
  1421. items = _free(items);
  1422. }
  1423. return NULL;
  1424. }
  1425. poptContext poptFreeContext(poptContext con)
  1426. {
  1427. if (con == NULL) return con;
  1428. poptResetContext(con);
  1429. con->os->argb = _free(con->os->argb);
  1430. con->aliases = poptFreeItems(con->aliases, con->numAliases);
  1431. con->numAliases = 0;
  1432. con->execs = poptFreeItems(con->execs, con->numExecs);
  1433. con->numExecs = 0;
  1434. con->leftovers = _free(con->leftovers);
  1435. con->finalArgv = _free(con->finalArgv);
  1436. con->appName = _free(con->appName);
  1437. con->otherHelp = _free(con->otherHelp);
  1438. con->execPath = _free(con->execPath);
  1439. con->arg_strip = PBM_FREE(con->arg_strip);
  1440. con = _free(con);
  1441. return con;
  1442. }
  1443. int poptAddAlias(poptContext con, struct poptAlias alias,
  1444. /*@unused@*/ UNUSED(int flags))
  1445. {
  1446. struct poptItem_s item_buf;
  1447. poptItem item = &item_buf;
  1448. memset(item, 0, sizeof(*item));
  1449. item->option.longName = alias.longName;
  1450. item->option.shortName = alias.shortName;
  1451. item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
  1452. item->option.arg = 0;
  1453. item->option.val = 0;
  1454. item->option.descrip = NULL;
  1455. item->option.argDescrip = NULL;
  1456. item->argc = alias.argc;
  1457. item->argv = alias.argv;
  1458. return poptAddItem(con, item, 0);
  1459. }
  1460. int poptAddItem(poptContext con, poptItem newItem, int flags)
  1461. {
  1462. poptItem * items, item;
  1463. int * nitems;
  1464. switch (flags) {
  1465. case 1:
  1466. items = &con->execs;
  1467. nitems = &con->numExecs;
  1468. break;
  1469. case 0:
  1470. items = &con->aliases;
  1471. nitems = &con->numAliases;
  1472. break;
  1473. default:
  1474. return 1;
  1475. /*@notreached@*/ break;
  1476. }
  1477. *items = realloc((*items), ((*nitems) + 1) * sizeof(**items));
  1478. if ((*items) == NULL)
  1479. return 1;
  1480. item = (*items) + (*nitems);
  1481. item->option.longName =
  1482. (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL);
  1483. item->option.shortName = newItem->option.shortName;
  1484. item->option.argInfo = newItem->option.argInfo;
  1485. item->option.arg = newItem->option.arg;
  1486. item->option.val = newItem->option.val;
  1487. item->option.descrip =
  1488. (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL);
  1489. item->option.argDescrip =
  1490. (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL);
  1491. item->argc = newItem->argc;
  1492. item->argv = newItem->argv;
  1493. (*nitems)++;
  1494. return 0;
  1495. }
  1496. const char * poptBadOption(poptContext con, unsigned int flags)
  1497. {
  1498. struct optionStackEntry * os = NULL;
  1499. if (con != NULL)
  1500. os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
  1501. return (os != NULL && os->argv != NULL ? os->argv[os->next - 1] : NULL);
  1502. }
  1503. const char * poptStrerror(const int error)
  1504. {
  1505. switch (error) {
  1506. case POPT_ERROR_NOARG:
  1507. return POPT_("missing argument");
  1508. case POPT_ERROR_BADOPT:
  1509. return POPT_("unknown option");
  1510. case POPT_ERROR_BADOPERATION:
  1511. return POPT_("mutually exclusive logical operations requested");
  1512. case POPT_ERROR_NULLARG:
  1513. return POPT_("opt->arg should not be NULL");
  1514. case POPT_ERROR_OPTSTOODEEP:
  1515. return POPT_("aliases nested too deeply");
  1516. case POPT_ERROR_BADQUOTE:
  1517. return POPT_("error in parameter quoting");
  1518. case POPT_ERROR_BADNUMBER:
  1519. return POPT_("invalid numeric value");
  1520. case POPT_ERROR_OVERFLOW:
  1521. return POPT_("number too large or too small");
  1522. case POPT_ERROR_MALLOC:
  1523. return POPT_("memory allocation failed");
  1524. case POPT_ERROR_BADCONFIG:
  1525. return POPT_("config file failed sanity test");
  1526. case POPT_ERROR_ERRNO:
  1527. return strerror(errno);
  1528. default:
  1529. return POPT_("unknown error");
  1530. }
  1531. }
  1532. int poptStuffArgs(poptContext con, const char ** argv)
  1533. {
  1534. int argc;
  1535. int rc;
  1536. if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
  1537. return POPT_ERROR_OPTSTOODEEP;
  1538. for (argc = 0; argv[argc]; argc++)
  1539. {};
  1540. con->os++;
  1541. con->os->next = 0;
  1542. con->os->nextArg = NULL;
  1543. con->os->nextCharArg = NULL;
  1544. con->os->currAlias = NULL;
  1545. rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
  1546. con->os->argb = NULL;
  1547. con->os->stuffed = 1;
  1548. return rc;
  1549. }
  1550. const char * poptGetInvocationName(poptContext con)
  1551. {
  1552. return (con->os->argv ? con->os->argv[0] : "");
  1553. }
  1554. int poptStrippedArgv(poptContext con, int argc, char ** argv)
  1555. {
  1556. int numargs = argc;
  1557. int j = 1;
  1558. int i;
  1559. /*@-sizeoftype@*/
  1560. if (con->arg_strip)
  1561. for (i = 1; i < argc; i++) {
  1562. if (PBM_ISSET(i, con->arg_strip))
  1563. numargs--;
  1564. }
  1565. for (i = 1; i < argc; i++) {
  1566. if (con->arg_strip && PBM_ISSET(i, con->arg_strip))
  1567. continue;
  1568. argv[j] = (j < numargs) ? argv[i] : NULL;
  1569. j++;
  1570. }
  1571. /*@=sizeoftype@*/
  1572. return numargs;
  1573. }