Annotation of embedaddon/ntp/sntp/libopts/save.c, revision 1.1.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>