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>