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