save.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. /*
  2. * \file save.c
  3. *
  4. * This module's routines will take the currently set options and
  5. * store them into an ".rc" file for re-interpretation the next
  6. * time the invoking program is run.
  7. *
  8. * @addtogroup autoopts
  9. * @{
  10. */
  11. /*
  12. * This file is part of AutoOpts, a companion to AutoGen.
  13. * AutoOpts is free software.
  14. * AutoOpts is Copyright (C) 1992-2016 by Bruce Korb - all rights reserved
  15. *
  16. * AutoOpts is available under any one of two licenses. The license
  17. * in use must be one of these two and the choice is under the control
  18. * of the user of the license.
  19. *
  20. * The GNU Lesser General Public License, version 3 or later
  21. * See the files "COPYING.lgplv3" and "COPYING.gplv3"
  22. *
  23. * The Modified Berkeley Software Distribution License
  24. * See the file "COPYING.mbsd"
  25. *
  26. * These files have the following sha256 sums:
  27. *
  28. * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
  29. * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
  30. * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
  31. */
  32. /* = = = START-STATIC-FORWARD = = = */
  33. static char const *
  34. find_dir_name(tOptions * opts, int * p_free);
  35. static char const *
  36. find_file_name(tOptions * opts, int * p_free_name);
  37. static void
  38. prt_entry(FILE * fp, tOptDesc * od, char const * l_arg);
  39. static void
  40. prt_value(FILE * fp, int depth, tOptDesc * pOD, tOptionValue const * ovp);
  41. static void
  42. prt_string(FILE * fp, char const * name, char const * pz);
  43. static void
  44. prt_val_list(FILE * fp, char const * name, tArgList * al);
  45. static void
  46. prt_nested(FILE * fp, tOptDesc * p);
  47. static FILE *
  48. open_sv_file(tOptions * opts);
  49. static void
  50. prt_no_arg_opt(FILE * fp, tOptDesc * p, tOptDesc * pOD);
  51. static void
  52. prt_str_arg(FILE * fp, tOptDesc * pOD);
  53. static void
  54. prt_enum_arg(FILE * fp, tOptDesc * od);
  55. static void
  56. prt_set_arg(FILE * fp, tOptDesc * od);
  57. static void
  58. prt_file_arg(FILE * fp, tOptDesc * od, tOptions * opts);
  59. /* = = = END-STATIC-FORWARD = = = */
  60. /**
  61. */
  62. static char const *
  63. find_dir_name(tOptions * opts, int * p_free)
  64. {
  65. char const * dir;
  66. if ( (opts->specOptIdx.save_opts == NO_EQUIVALENT)
  67. || (opts->specOptIdx.save_opts == 0))
  68. return NULL;
  69. dir = opts->pOptDesc[ opts->specOptIdx.save_opts ].optArg.argString;
  70. if ((dir != NULL) && (*dir != NUL))
  71. return dir;
  72. /*
  73. * This function only works if there is a directory where
  74. * we can stash the RC (INI) file.
  75. */
  76. {
  77. char const * const * papz = opts->papzHomeList;
  78. if (papz == NULL)
  79. return NULL;
  80. while (papz[1] != NULL) papz++;
  81. dir = *papz;
  82. }
  83. /*
  84. * IF it does not require deciphering an env value, then just copy it
  85. */
  86. if (*dir != '$')
  87. return dir;
  88. {
  89. char const * end = strchr(++dir, DIRCH);
  90. char * env;
  91. if (end != NULL) {
  92. char z[ AO_NAME_SIZE ];
  93. if ((end - dir) > AO_NAME_LIMIT )
  94. return NULL;
  95. memcpy(z, dir, (size_t)(end - dir));
  96. z[end - dir] = NUL;
  97. env = getenv(z);
  98. } else {
  99. /*
  100. * Make sure we can get the env value (after stripping off
  101. * any trailing directory or file names)
  102. */
  103. env = getenv(dir);
  104. }
  105. if (env == NULL) {
  106. fprintf(stderr, zsave_warn, opts->pzProgName);
  107. fprintf(stderr, zNotDef, dir);
  108. return NULL;
  109. }
  110. if (end == NULL)
  111. return env;
  112. /*
  113. * we will be returning an allocated result
  114. */
  115. *p_free = 1;
  116. {
  117. size_t env_len = strlen(env);
  118. size_t end_len = strlen(end);
  119. char * p;
  120. char * res = p = (char *)AGALOC(env_len + end_len + 2, "dir name");
  121. memcpy(p, env, env_len);
  122. p += env_len;
  123. *(p++) = '/';
  124. memcpy(p, end, end_len + 1);
  125. return res;
  126. }
  127. }
  128. }
  129. /**
  130. */
  131. static char const *
  132. find_file_name(tOptions * opts, int * p_free_name)
  133. {
  134. struct stat stBuf;
  135. int free_dir_name = 0;
  136. char const * pzDir = find_dir_name(opts, &free_dir_name);
  137. if (pzDir == NULL)
  138. return NULL;
  139. /*
  140. * See if we can find the specified directory. We use a once-only loop
  141. * structure so we can bail out early.
  142. */
  143. if (stat(pzDir, &stBuf) != 0) do {
  144. char z[AG_PATH_MAX];
  145. char * dirchp;
  146. /*
  147. * IF we could not, check to see if we got a full
  148. * path to a file name that has not been created yet.
  149. */
  150. if (errno != ENOENT) {
  151. bogus_name:
  152. fprintf(stderr, zsave_warn, opts->pzProgName);
  153. fprintf(stderr, zNoStat, errno, strerror(errno), pzDir);
  154. if (free_dir_name)
  155. AGFREE(pzDir);
  156. return NULL;
  157. }
  158. /*
  159. * Strip off the last component, stat the remaining string and
  160. * that string must name a directory
  161. */
  162. dirchp = strrchr(pzDir, DIRCH);
  163. if (dirchp == NULL) {
  164. stBuf.st_mode = S_IFREG;
  165. break; /* found directory -- viz., "." */
  166. }
  167. if ((size_t)(dirchp - pzDir) >= sizeof(z))
  168. goto bogus_name;
  169. memcpy(z, pzDir, (size_t)(dirchp - pzDir));
  170. z[dirchp - pzDir] = NUL;
  171. if ((stat(z, &stBuf) != 0) || ! S_ISDIR(stBuf.st_mode))
  172. goto bogus_name;
  173. stBuf.st_mode = S_IFREG; /* file within this directory */
  174. } while (false);
  175. /*
  176. * IF what we found was a directory,
  177. * THEN tack on the config file name
  178. */
  179. if (S_ISDIR(stBuf.st_mode)) {
  180. {
  181. size_t sz = strlen(pzDir) + strlen(opts->pzRcName) + 2;
  182. char * pzPath = (char *)AGALOC(sz, "file name");
  183. if ( snprintf(pzPath, sz, "%s/%s", pzDir, opts->pzRcName)
  184. >= (int)sz)
  185. option_exits(EXIT_FAILURE);
  186. if (free_dir_name)
  187. AGFREE(pzDir);
  188. pzDir = pzPath;
  189. free_dir_name = 1;
  190. }
  191. /*
  192. * IF we cannot stat the object for any reason other than
  193. * it does not exist, then we bail out
  194. */
  195. if (stat(pzDir, &stBuf) != 0) {
  196. if (errno != ENOENT) {
  197. fprintf(stderr, zsave_warn, opts->pzProgName);
  198. fprintf(stderr, zNoStat, errno, strerror(errno),
  199. pzDir);
  200. AGFREE(pzDir);
  201. return NULL;
  202. }
  203. /*
  204. * It does not exist yet, but it will be a regular file
  205. */
  206. stBuf.st_mode = S_IFREG;
  207. }
  208. }
  209. /*
  210. * Make sure that whatever we ultimately found, that it either is
  211. * or will soon be a file.
  212. */
  213. if (! S_ISREG(stBuf.st_mode)) {
  214. fprintf(stderr, zsave_warn, opts->pzProgName, pzDir);
  215. if (free_dir_name)
  216. AGFREE(pzDir);
  217. return NULL;
  218. }
  219. /*
  220. * Get rid of the old file
  221. */
  222. unlink(pzDir);
  223. *p_free_name = free_dir_name;
  224. return pzDir;
  225. }
  226. /**
  227. * print one option entry to the save file.
  228. *
  229. * @param[in] fp the file pointer for the save file
  230. * @param[in] od the option descriptor to print
  231. * @param[in] l_arg the last argument for the option
  232. */
  233. static void
  234. prt_entry(FILE * fp, tOptDesc * od, char const * l_arg)
  235. {
  236. int space_ct;
  237. /*
  238. * There is an argument. Pad the name so values line up.
  239. * Not disabled *OR* this got equivalenced to another opt,
  240. * then use current option name.
  241. * Otherwise, there must be a disablement name.
  242. */
  243. {
  244. char const * pz =
  245. (! DISABLED_OPT(od) || (od->optEquivIndex != NO_EQUIVALENT))
  246. ? od->pz_Name
  247. : od->pz_DisableName;
  248. space_ct = 17 - strlen(pz);
  249. fputs(pz, fp);
  250. }
  251. if ( (l_arg == NULL)
  252. && (OPTST_GET_ARGTYPE(od->fOptState) != OPARG_TYPE_NUMERIC))
  253. goto end_entry;
  254. fputs(" = ", fp);
  255. while (space_ct-- > 0) fputc(' ', fp);
  256. /*
  257. * IF the option is numeric only,
  258. * THEN the char pointer is really the number
  259. */
  260. if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NUMERIC)
  261. fprintf(fp, "%d", (int)(intptr_t)l_arg);
  262. else {
  263. for (;;) {
  264. char const * eol = strchr(l_arg, NL);
  265. /*
  266. * IF this is the last line
  267. * THEN bail and print it
  268. */
  269. if (eol == NULL)
  270. break;
  271. /*
  272. * Print the continuation and the text from the current line
  273. */
  274. (void)fwrite(l_arg, (size_t)(eol - l_arg), (size_t)1, fp);
  275. l_arg = eol+1; /* advance the Last Arg pointer */
  276. fputs("\\\n", fp);
  277. }
  278. /*
  279. * Terminate the entry
  280. */
  281. fputs(l_arg, fp);
  282. }
  283. end_entry:
  284. fputc(NL, fp);
  285. }
  286. /**
  287. */
  288. static void
  289. prt_value(FILE * fp, int depth, tOptDesc * pOD, tOptionValue const * ovp)
  290. {
  291. while (--depth >= 0)
  292. putc(' ', fp), putc(' ', fp);
  293. switch (ovp->valType) {
  294. default:
  295. case OPARG_TYPE_NONE:
  296. fprintf(fp, NULL_ATR_FMT, ovp->pzName);
  297. break;
  298. case OPARG_TYPE_STRING:
  299. prt_string(fp, ovp->pzName, ovp->v.strVal);
  300. break;
  301. case OPARG_TYPE_ENUMERATION:
  302. case OPARG_TYPE_MEMBERSHIP:
  303. if (pOD != NULL) {
  304. uint32_t opt_state = pOD->fOptState;
  305. uintptr_t val = pOD->optArg.argEnum;
  306. char const * typ = (ovp->valType == OPARG_TYPE_ENUMERATION)
  307. ? "keyword" : "set-membership";
  308. fprintf(fp, TYPE_ATR_FMT, ovp->pzName, typ);
  309. /*
  310. * This is a magic incantation that will convert the
  311. * bit flag values back into a string suitable for printing.
  312. */
  313. (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD );
  314. if (pOD->optArg.argString != NULL) {
  315. fputs(pOD->optArg.argString, fp);
  316. if (ovp->valType != OPARG_TYPE_ENUMERATION) {
  317. /*
  318. * set membership strings get allocated
  319. */
  320. AGFREE(pOD->optArg.argString);
  321. }
  322. }
  323. pOD->optArg.argEnum = val;
  324. pOD->fOptState = opt_state;
  325. fprintf(fp, END_XML_FMT, ovp->pzName);
  326. break;
  327. }
  328. /* FALLTHROUGH */
  329. case OPARG_TYPE_NUMERIC:
  330. fprintf(fp, NUMB_ATR_FMT, ovp->pzName, ovp->v.longVal);
  331. break;
  332. case OPARG_TYPE_BOOLEAN:
  333. fprintf(fp, BOOL_ATR_FMT, ovp->pzName,
  334. ovp->v.boolVal ? "true" : "false");
  335. break;
  336. case OPARG_TYPE_HIERARCHY:
  337. prt_val_list(fp, ovp->pzName, ovp->v.nestVal);
  338. break;
  339. }
  340. }
  341. /**
  342. */
  343. static void
  344. prt_string(FILE * fp, char const * name, char const * pz)
  345. {
  346. fprintf(fp, OPEN_XML_FMT, name);
  347. for (;;) {
  348. int ch = ((int)*(pz++)) & 0xFF;
  349. switch (ch) {
  350. case NUL: goto string_done;
  351. case '&':
  352. case '<':
  353. case '>':
  354. #if __GNUC__ >= 4
  355. case 1 ... (' ' - 1):
  356. case ('~' + 1) ... 0xFF:
  357. #endif
  358. emit_special_char(fp, ch);
  359. break;
  360. default:
  361. #if __GNUC__ < 4
  362. if ( ((ch >= 1) && (ch <= (' ' - 1)))
  363. || ((ch >= ('~' + 1)) && (ch <= 0xFF)) ) {
  364. emit_special_char(fp, ch);
  365. break;
  366. }
  367. #endif
  368. putc(ch, fp);
  369. }
  370. } string_done:;
  371. fprintf(fp, END_XML_FMT, name);
  372. }
  373. /**
  374. */
  375. static void
  376. prt_val_list(FILE * fp, char const * name, tArgList * al)
  377. {
  378. static int depth = 1;
  379. int sp_ct;
  380. int opt_ct;
  381. void ** opt_list;
  382. if (al == NULL)
  383. return;
  384. opt_ct = al->useCt;
  385. opt_list = (void **)al->apzArgs;
  386. if (opt_ct <= 0) {
  387. fprintf(fp, OPEN_CLOSE_FMT, name);
  388. return;
  389. }
  390. fprintf(fp, NESTED_OPT_FMT, name);
  391. depth++;
  392. while (--opt_ct >= 0) {
  393. tOptionValue const * ovp = *(opt_list++);
  394. prt_value(fp, depth, NULL, ovp);
  395. }
  396. depth--;
  397. for (sp_ct = depth; --sp_ct >= 0;)
  398. putc(' ', fp), putc(' ', fp);
  399. fprintf(fp, "</%s>\n", name);
  400. }
  401. /**
  402. */
  403. static void
  404. prt_nested(FILE * fp, tOptDesc * p)
  405. {
  406. int opt_ct;
  407. tArgList * al = p->optCookie;
  408. void ** opt_list;
  409. if (al == NULL)
  410. return;
  411. opt_ct = al->useCt;
  412. opt_list = (void **)al->apzArgs;
  413. if (opt_ct <= 0)
  414. return;
  415. do {
  416. tOptionValue const * base = *(opt_list++);
  417. tOptionValue const * ovp = optionGetValue(base, NULL);
  418. if (ovp == NULL)
  419. continue;
  420. fprintf(fp, NESTED_OPT_FMT, p->pz_Name);
  421. do {
  422. prt_value(fp, 1, p, ovp);
  423. } while (ovp = optionNextValue(base, ovp),
  424. ovp != NULL);
  425. fprintf(fp, "</%s>\n", p->pz_Name);
  426. } while (--opt_ct > 0);
  427. }
  428. /**
  429. * open the file for saving option state.
  430. *
  431. * @param[in] opts the program options structure
  432. * @returns the open file pointer. It may be NULL.
  433. */
  434. static FILE *
  435. open_sv_file(tOptions * opts)
  436. {
  437. FILE * fp;
  438. {
  439. int free_name = 0;
  440. char const * pzFName = find_file_name(opts, &free_name);
  441. if (pzFName == NULL)
  442. return NULL;
  443. fp = fopen(pzFName, "w" FOPEN_BINARY_FLAG);
  444. if (fp == NULL) {
  445. fprintf(stderr, zsave_warn, opts->pzProgName);
  446. fprintf(stderr, zNoCreat, errno, strerror(errno), pzFName);
  447. if (free_name)
  448. AGFREE(pzFName);
  449. return fp;
  450. }
  451. if (free_name)
  452. AGFREE(pzFName);
  453. }
  454. fputs("# ", fp);
  455. {
  456. char const * e = strchr(opts->pzUsageTitle, NL);
  457. if (e++ != NULL)
  458. fwrite(opts->pzUsageTitle, 1, e - opts->pzUsageTitle, fp);
  459. }
  460. {
  461. time_t cur_time = time(NULL);
  462. char * time_str = ctime(&cur_time);
  463. fprintf(fp, zPresetFile, time_str);
  464. #ifdef HAVE_ALLOCATED_CTIME
  465. /*
  466. * The return values for ctime(), localtime(), and gmtime()
  467. * normally point to static data that is overwritten by each call.
  468. * The test to detect allocated ctime, so we leak the memory.
  469. */
  470. AGFREE(time_str);
  471. #endif
  472. }
  473. return fp;
  474. }
  475. /**
  476. */
  477. static void
  478. prt_no_arg_opt(FILE * fp, tOptDesc * p, tOptDesc * pOD)
  479. {
  480. /*
  481. * The aliased to argument indicates whether or not the option
  482. * is "disabled". However, the original option has the name
  483. * string, so we get that there, not with "p".
  484. */
  485. char const * pznm =
  486. (DISABLED_OPT(p)) ? pOD->pz_DisableName : pOD->pz_Name;
  487. /*
  488. * If the option was disabled and the disablement name is NULL,
  489. * then the disablement was caused by aliasing.
  490. * Use the name as the string to emit.
  491. */
  492. if (pznm == NULL)
  493. pznm = pOD->pz_Name;
  494. fprintf(fp, "%s\n", pznm);
  495. }
  496. /**
  497. */
  498. static void
  499. prt_str_arg(FILE * fp, tOptDesc * pOD)
  500. {
  501. if (pOD->fOptState & OPTST_STACKED) {
  502. tArgList * pAL = (tArgList *)pOD->optCookie;
  503. int uct = pAL->useCt;
  504. char const ** ppz = pAL->apzArgs;
  505. /*
  506. * un-disable multiple copies of disabled options.
  507. */
  508. if (uct > 1)
  509. pOD->fOptState &= ~OPTST_DISABLED;
  510. while (uct-- > 0)
  511. prt_entry(fp, pOD, *(ppz++));
  512. } else {
  513. prt_entry(fp, pOD, pOD->optArg.argString);
  514. }
  515. }
  516. /**
  517. * print the string value of an enumeration.
  518. *
  519. * @param[in] fp the file pointer to write to
  520. * @param[in] od the option descriptor with the enumerated value
  521. */
  522. static void
  523. prt_enum_arg(FILE * fp, tOptDesc * od)
  524. {
  525. uintptr_t val = od->optArg.argEnum;
  526. /*
  527. * This is a magic incantation that will convert the
  528. * bit flag values back into a string suitable for printing.
  529. */
  530. (*(od->pOptProc))(OPTPROC_RETURN_VALNAME, od);
  531. prt_entry(fp, od, VOIDP(od->optArg.argString));
  532. od->optArg.argEnum = val;
  533. }
  534. /**
  535. * Print the bits set in a bit mask option.
  536. * We call the option handling function with a magic value for
  537. * the options pointer and it allocates and fills in the string.
  538. * We print that with a call to prt_entry().
  539. *
  540. * @param[in] fp the file pointer to write to
  541. * @param[in] od the option descriptor with a bit mask value type
  542. */
  543. static void
  544. prt_set_arg(FILE * fp, tOptDesc * od)
  545. {
  546. char * list = optionMemberList(od);
  547. size_t len = strlen(list);
  548. char * buf = (char *)AGALOC(len + 3, "dir name");
  549. *buf= '=';
  550. memcpy(buf+1, list, len + 1);
  551. prt_entry(fp, od, buf);
  552. AGFREE(buf);
  553. AGFREE(list);
  554. }
  555. /**
  556. * figure out what the option file name argument is.
  557. * If one can be found, call prt_entry() to emit it.
  558. *
  559. * @param[in] fp the file pointer to write to.
  560. * @param[in] od the option descriptor with a bit mask value type
  561. * @param[in] opts the program options descriptor
  562. */
  563. static void
  564. prt_file_arg(FILE * fp, tOptDesc * od, tOptions * opts)
  565. {
  566. /*
  567. * If the cookie is not NULL, then it has the file name, period.
  568. * Otherwise, if we have a non-NULL string argument, then....
  569. */
  570. if (od->optCookie != NULL)
  571. prt_entry(fp, od, od->optCookie);
  572. else if (HAS_originalOptArgArray(opts)) {
  573. char const * orig =
  574. opts->originalOptArgArray[od->optIndex].argString;
  575. if (od->optArg.argString == orig)
  576. return;
  577. prt_entry(fp, od, od->optArg.argString);
  578. }
  579. }
  580. /*=export_func optionSaveFile
  581. *
  582. * what: saves the option state to a file
  583. *
  584. * arg: tOptions *, opts, program options descriptor
  585. *
  586. * doc:
  587. *
  588. * This routine will save the state of option processing to a file. The name
  589. * of that file can be specified with the argument to the @code{--save-opts}
  590. * option, or by appending the @code{rcfile} attribute to the last
  591. * @code{homerc} attribute. If no @code{rcfile} attribute was specified, it
  592. * will default to @code{.@i{programname}rc}. If you wish to specify another
  593. * file, you should invoke the @code{SET_OPT_SAVE_OPTS(@i{filename})} macro.
  594. *
  595. * The recommend usage is as follows:
  596. * @example
  597. * optionProcess(&progOptions, argc, argv);
  598. * if (i_want_a_non_standard_place_for_this)
  599. * SET_OPT_SAVE_OPTS("myfilename");
  600. * optionSaveFile(&progOptions);
  601. * @end example
  602. *
  603. * err:
  604. *
  605. * If no @code{homerc} file was specified, this routine will silently return
  606. * and do nothing. If the output file cannot be created or updated, a message
  607. * will be printed to @code{stderr} and the routine will return.
  608. =*/
  609. void
  610. optionSaveFile(tOptions * opts)
  611. {
  612. tOptDesc * od;
  613. int ct;
  614. FILE * fp = open_sv_file(opts);
  615. if (fp == NULL)
  616. return;
  617. /*
  618. * FOR each of the defined options, ...
  619. */
  620. ct = opts->presetOptCt;
  621. od = opts->pOptDesc;
  622. do {
  623. tOptDesc * p;
  624. /*
  625. * IF the option has not been defined
  626. * OR it does not take an initialization value
  627. * OR it is equivalenced to another option
  628. * THEN continue (ignore it)
  629. *
  630. * Equivalenced options get picked up when the equivalenced-to
  631. * option is processed.
  632. */
  633. if (UNUSED_OPT(od))
  634. continue;
  635. if ((od->fOptState & OPTST_DO_NOT_SAVE_MASK) != 0)
  636. continue;
  637. if ( (od->optEquivIndex != NO_EQUIVALENT)
  638. && (od->optEquivIndex != od->optIndex))
  639. continue;
  640. /*
  641. * The option argument data are found at the equivalenced-to option,
  642. * but the actual option argument type comes from the original
  643. * option descriptor. Be careful!
  644. */
  645. p = ((od->fOptState & OPTST_EQUIVALENCE) != 0)
  646. ? (opts->pOptDesc + od->optActualIndex) : od;
  647. switch (OPTST_GET_ARGTYPE(od->fOptState)) {
  648. case OPARG_TYPE_NONE:
  649. prt_no_arg_opt(fp, p, od);
  650. break;
  651. case OPARG_TYPE_NUMERIC:
  652. prt_entry(fp, p, VOIDP(p->optArg.argInt));
  653. break;
  654. case OPARG_TYPE_STRING:
  655. prt_str_arg(fp, p);
  656. break;
  657. case OPARG_TYPE_ENUMERATION:
  658. prt_enum_arg(fp, p);
  659. break;
  660. case OPARG_TYPE_MEMBERSHIP:
  661. prt_set_arg(fp, p);
  662. break;
  663. case OPARG_TYPE_BOOLEAN:
  664. prt_entry(fp, p, p->optArg.argBool ? "true" : "false");
  665. break;
  666. case OPARG_TYPE_HIERARCHY:
  667. prt_nested(fp, p);
  668. break;
  669. case OPARG_TYPE_FILE:
  670. prt_file_arg(fp, p, opts);
  671. break;
  672. default:
  673. break; /* cannot handle - skip it */
  674. }
  675. } while (od++, (--ct > 0));
  676. fclose(fp);
  677. }
  678. /** @}
  679. *
  680. * Local Variables:
  681. * mode: C
  682. * c-file-style: "stroustrup"
  683. * indent-tabs-mode: nil
  684. * End:
  685. * end of autoopts/save.c */