"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

options.c

Go to the documentation of this file.
00001 /*
00002  * options.c - options package routines
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *  
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  * 
00009  * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  * 
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  * 
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: options.c,v 1.1.1.1 2000/05/26 15:18:57 taustin Exp $
00053  *
00054  * $Log: options.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:18:57  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.3  1998/08/31 17:10:39  taustin
00060  * ported to MS VC++
00061  *
00062  * Revision 1.2  1998/08/27 15:47:46  taustin
00063  * implemented host interface description in host.h
00064  * options package fixes: on/off supported for booleans, relative
00065  *       pathnames, negative integers are now parsed correctly
00066  *
00067  * Revision 1.1  1997/03/11  01:31:45  taustin
00068  * Initial revision
00069  *
00070  *
00071  */
00072 
00073 #include <stdio.h>
00074 #include <stdlib.h>
00075 #ifndef _MSC_VER
00076 #include <unistd.h>
00077 #else /* _MSC_VER */
00078 #define chdir   _chdir
00079 #define getcwd  _getcwd
00080 #endif
00081 #include <string.h>
00082 #include <ctype.h>
00083 #include <float.h>
00084 
00085 #include "host.h"
00086 #include "misc.h"
00087 #include "options.h"
00088 
00089 /* create a new option database */
00090 struct opt_odb_t *
00091 opt_new(orphan_fn_t orphan_fn)  /* user-specified orphan parser */
00092 {
00093   struct opt_odb_t *odb;
00094 
00095   odb = (struct opt_odb_t *)calloc(1, sizeof(struct opt_odb_t));
00096   if (!odb)
00097     fatal("out of virtual memory");
00098 
00099   odb->options = NULL;
00100   odb->orphan_fn = orphan_fn;
00101   odb->header = NULL;
00102   odb->notes = NULL;
00103 
00104   return odb;
00105 }
00106 
00107 /* free an option database */
00108 void
00109 opt_delete(struct opt_odb_t *odb)       /* option database */
00110 {
00111   struct opt_opt_t *opt, *opt_next;
00112   struct opt_note_t *note, *note_next;
00113 
00114   /* free all options */
00115   for (opt=odb->options; opt; opt=opt_next)
00116     {
00117       opt_next = opt->next;
00118       opt->next = NULL;
00119       free(opt);
00120     }
00121 
00122   /* free all notes */
00123   for (note = odb->notes; note != NULL; note = note_next)
00124     {
00125       note_next = note->next;
00126       note->next = NULL;
00127       free(note);
00128     }
00129   odb->notes = NULL;
00130 
00131   free(odb);
00132 }
00133 
00134 /* add option OPT to option database ODB */
00135 static void
00136 add_option(struct opt_odb_t *odb,       /* option database */
00137            struct opt_opt_t *opt)       /* option variable */
00138 {
00139   struct opt_opt_t *elt, *prev;
00140 
00141   /* sanity checks on option name */
00142   if (opt->name[0] != '-')
00143     panic("option `%s' must start with a `-'", opt->name);
00144 
00145   /* add to end of option list */
00146   for (prev=NULL, elt=odb->options; elt != NULL; prev=elt, elt=elt->next)
00147     {
00148       /* sanity checks on option name */
00149       if (elt->name[0] == opt->name[0] && !strcmp(elt->name, opt->name))
00150         panic("option `%s' is multiply defined", opt->name);
00151     }
00152 
00153   if (prev != NULL)
00154     prev->next = opt;
00155   else /* prev == NULL */
00156     odb->options = opt;
00157   opt->next = NULL;
00158 }
00159 
00160 /* register an integer option variable */
00161 void
00162 opt_reg_int(struct opt_odb_t *odb,      /* option data base */
00163             char *name,                 /* option name */
00164             char *desc,                 /* option description */
00165             int *var,                   /* target variable */
00166             int def_val,                /* default variable value */
00167             int print,                  /* print during `-dumpconfig'? */
00168             char *format)               /* optional value print format */
00169 {
00170   struct opt_opt_t *opt;
00171 
00172   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00173   if (!opt)
00174     fatal("out of virtual memory");
00175 
00176   opt->name = name;
00177   opt->desc = desc;
00178   opt->nvars = 1;
00179   opt->nelt = NULL;
00180   opt->format = format ? format : "%12d";
00181   opt->oc = oc_int;
00182   opt->variant.for_int.var = var;
00183   opt->print = print;
00184   opt->accrue = FALSE;
00185 
00186   /* place on ODB's option list */
00187   opt->next = NULL;
00188   add_option(odb, opt);
00189 
00190   /* set default value */
00191   *var = def_val;
00192 }
00193 
00194 /* register an integer option list */
00195 void
00196 opt_reg_int_list(struct opt_odb_t *odb,/* option database */
00197                  char *name,            /* option name */
00198                  char *desc,            /* option description */
00199                  int *vars,             /* pointer to option array */
00200                  int nvars,             /* total entries in option array */
00201                  int *nelt,             /* number of entries parsed */
00202                  int *def_val,          /* default value of option array */
00203                  int print,             /* print during `-dumpconfig'? */
00204                  char *format,          /* optional user print format */
00205                  int accrue)            /* accrue list across uses */
00206 {
00207   int i;
00208   struct opt_opt_t *opt;
00209 
00210   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00211   if (!opt)
00212     fatal("out of virtual memory");
00213 
00214   opt->name = name;
00215   opt->desc = desc;
00216   opt->nvars = nvars;
00217   opt->nelt = nelt;
00218   opt->format = format ? format : "%d";
00219   opt->oc = oc_int;
00220   opt->variant.for_int.var = vars;
00221   opt->print = print;
00222   opt->accrue = accrue;
00223 
00224   /* place on ODB's option list */
00225   opt->next = NULL;
00226   add_option(odb, opt);
00227 
00228   /* set default value */
00229   for (i=0; i < *nelt; i++)
00230     vars[i] = def_val[i];
00231 }
00232 
00233 /* register an unsigned integer option variable */
00234 void
00235 opt_reg_uint(struct opt_odb_t *odb,     /* option database */
00236              char *name,                /* option name */
00237              char *desc,                /* option description */
00238              unsigned int *var,         /* pointer to option variable */
00239              unsigned int def_val,      /* default value of option variable */
00240              int print,                 /* print during `-dumpconfig'? */
00241              char *format)              /* optional user print format */
00242 {
00243   struct opt_opt_t *opt;
00244 
00245   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00246   if (!opt)
00247     fatal("out of virtual memory");
00248 
00249   opt->name = name;
00250   opt->desc = desc;
00251   opt->nvars = 1;
00252   opt->nelt = NULL;
00253   opt->format = format ? format : "%12u";
00254   opt->oc = oc_uint;
00255   opt->variant.for_uint.var = var;
00256   opt->print = print;
00257   opt->accrue = FALSE;
00258 
00259   /* place on ODB's option list */
00260   opt->next = NULL;
00261   add_option(odb, opt);
00262 
00263   /* set default value */
00264   *var = def_val;
00265 }
00266 
00267 /* register an unsigned integer option list */
00268 void
00269 opt_reg_uint_list(struct opt_odb_t *odb,/* option database */
00270                   char *name,           /* option name */
00271                   char *desc,           /* option description */
00272                   unsigned int *vars,   /* pointer to option array */
00273                   int nvars,            /* total entries in option array */
00274                   int *nelt,            /* number of elements parsed */
00275                   unsigned int *def_val,/* default value of option array */
00276                   int print,            /* print opt during `-dumpconfig'? */
00277                   char *format,         /* optional user print format */
00278                   int accrue)           /* accrue list across uses */
00279 {
00280   int i;
00281   struct opt_opt_t *opt;
00282 
00283   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00284   if (!opt)
00285     fatal("out of virtual memory");
00286 
00287   opt->name = name;
00288   opt->desc = desc;
00289   opt->nvars = nvars;
00290   opt->nelt = nelt;
00291   opt->format = format ? format : "%u";
00292   opt->oc = oc_uint;
00293   opt->variant.for_uint.var = vars;
00294   opt->print = print;
00295   opt->accrue = accrue;
00296 
00297   /* place on ODB's option list */
00298   opt->next = NULL;
00299   add_option(odb, opt);
00300 
00301   /* set default value */
00302   for (i=0; i < *nelt; i++)
00303     vars[i] = def_val[i];
00304 }
00305 
00306 /* register a single-precision floating point option variable */
00307 void
00308 opt_reg_float(struct opt_odb_t *odb,    /* option data base */
00309               char *name,               /* option name */
00310               char *desc,               /* option description */
00311               float *var,               /* target option variable */
00312               float def_val,            /* default variable value */
00313               int print,                /* print during `-dumpconfig'? */
00314               char *format)             /* optional value print format */
00315 {
00316   struct opt_opt_t *opt;
00317 
00318   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00319   if (!opt)
00320     fatal("out of virtual memory");
00321 
00322   opt->name = name;
00323   opt->desc = desc;
00324   opt->nvars = 1;
00325   opt->nelt = NULL;
00326   opt->format = format ? format : "%12.4f";
00327   opt->oc = oc_float;
00328   opt->variant.for_float.var = var;
00329   opt->print = print;
00330   opt->accrue = FALSE;
00331 
00332   /* place on ODB's option list */
00333   opt->next = NULL;
00334   add_option(odb, opt);
00335 
00336   /* set default value */
00337   *var = def_val;
00338 }
00339 
00340 /* register a single-precision floating point option array */
00341 void
00342 opt_reg_float_list(struct opt_odb_t *odb,/* option data base */
00343                    char *name,          /* option name */
00344                    char *desc,          /* option description */
00345                    float *vars,         /* target array */
00346                    int nvars,           /* target array size */
00347                    int *nelt,           /* number of args parsed goes here */
00348                    float *def_val,      /* default variable value */
00349                    int print,           /* print during `-dumpconfig'? */
00350                    char *format,        /* optional value print format */
00351                    int accrue)          /* accrue list across uses */
00352 {
00353   int i;
00354   struct opt_opt_t *opt;
00355 
00356   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00357   if (!opt)
00358     fatal("out of virtual memory");
00359 
00360   opt->name = name;
00361   opt->desc = desc;
00362   opt->nvars = nvars;
00363   opt->nelt = nelt;
00364   opt->format = format ? format : "%.4f";
00365   opt->oc = oc_float;
00366   opt->variant.for_float.var = vars;
00367   opt->print = print;
00368   opt->accrue = accrue;
00369 
00370   /* place on ODB's option list */
00371   opt->next = NULL;
00372   add_option(odb, opt);
00373 
00374   /* set default value */
00375   for (i=0; i < *nelt; i++)
00376     vars[i] = def_val[i];
00377 }
00378 
00379 /* register a double-precision floating point option variable */
00380 void
00381 opt_reg_double(struct opt_odb_t *odb,   /* option data base */
00382                char *name,              /* option name */
00383                char *desc,              /* option description */
00384                double *var,             /* target variable */
00385                double def_val,          /* default variable value */
00386                int print,               /* print during `-dumpconfig'? */
00387                char *format)            /* option value print format */
00388 {
00389   struct opt_opt_t *opt;
00390 
00391   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00392   if (!opt)
00393     fatal("out of virtual memory");
00394 
00395   opt->name = name;
00396   opt->desc = desc;
00397   opt->nvars = 1;
00398   opt->nelt = NULL;
00399   opt->format = format ? format : "%12.4f";
00400   opt->oc = oc_double;
00401   opt->variant.for_double.var = var;
00402   opt->print = print;
00403   opt->accrue = FALSE;
00404 
00405   /* place on ODB's option list */
00406   opt->next = NULL;
00407   add_option(odb, opt);
00408 
00409   /* set default value */
00410   *var = def_val;
00411 }
00412 
00413 /* register a double-precision floating point option array */
00414 void
00415 opt_reg_double_list(struct opt_odb_t *odb, /* option data base */
00416                     char *name,         /* option name */
00417                     char *desc,         /* option description */
00418                     double *vars,       /* target array */
00419                     int nvars,          /* target array size */
00420                     int *nelt,          /* number of args parsed goes here */
00421                     double *def_val,    /* default variable value */
00422                     int print,          /* print during `-dumpconfig'? */
00423                     char *format,       /* option value print format */
00424                     int accrue)         /* accrue list across uses */
00425 {
00426   int i;
00427   struct opt_opt_t *opt;
00428 
00429   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00430   if (!opt)
00431     fatal("out of virtual memory");
00432 
00433   opt->name = name;
00434   opt->desc = desc;
00435   opt->nvars = nvars;
00436   opt->nelt = nelt;
00437   opt->format = format ? format : "%.4f";
00438   opt->oc = oc_double;
00439   opt->variant.for_double.var = vars;
00440   opt->print = print;
00441   opt->accrue = accrue;
00442 
00443   /* place on ODB's option list */
00444   opt->next = NULL;
00445   add_option(odb, opt);
00446 
00447   /* set default value */
00448   for (i=0; i < *nelt; i++)
00449     vars[i] = def_val[i];
00450 }
00451 
00452 /* bind an enumeration string to an enumeration value */
00453 static int
00454 bind_to_enum(char *str,                 /* string to bind to an enum */
00455              char **emap,               /* enumeration string map */
00456              int *eval,                 /* enumeration value map, optional */
00457              int emap_sz,               /* size of maps */
00458              int *res)                  /* enumeration string value result */
00459 {
00460   int i;
00461 
00462   /* string enumeration string map */
00463   for (i=0; i<emap_sz; i++)
00464     {
00465       if (!strcmp(str, emap[i]))
00466         {
00467           if (eval)
00468             {
00469               /* bind to eval value */
00470               *res = eval[i];
00471             }
00472           else
00473             {
00474               /* bind to string index */
00475               *res = i;
00476             }
00477           return TRUE;
00478         }
00479     }
00480 
00481   /* not found */
00482   *res = -1;
00483   return FALSE;
00484 }
00485 
00486 /* bind a enumeration value to an enumeration string */
00487 static char *
00488 bind_to_str(int val,                    /* enumeration value */
00489             char **emap,                /* enumeration string map */
00490             int *eval,                  /* enumeration value map, optional */
00491             int emap_sz)                /* size of maps */
00492 {
00493   int i;
00494 
00495   if (eval)
00496     {
00497       /* bind to first matching eval value */
00498       for (i=0; i<emap_sz; i++)
00499         {
00500           if (eval[i] == val)
00501             {
00502               /* found */
00503               return emap[i];
00504             }
00505         }
00506       /* not found */
00507       return NULL;
00508     }
00509   else
00510     {
00511       /* bind to string at index */
00512       if (val >= emap_sz)
00513         {
00514           /* invalid index */
00515           return NULL;
00516         }
00517       /* else, index is in range */
00518       return emap[val];
00519     }
00520 }
00521 
00522 /* register an enumeration option variable, NOTE: all enumeration option
00523    variables must be of type `int', since true enum variables may be allocated
00524    with variable sizes by some compilers */
00525 void
00526 opt_reg_enum(struct opt_odb_t *odb,     /* option data base */
00527              char *name,                /* option name */
00528              char *desc,                /* option description */
00529              int *var,                  /* target variable */
00530              char *def_val,             /* default variable value */
00531              char **emap,               /* enumeration string map */
00532              int *eval,                 /* enumeration value map, optional */
00533              int emap_sz,               /* size of maps */
00534              int print,                 /* print during `-dumpconfig'? */
00535              char *format)              /* option value print format */
00536 {
00537   int enum_val;
00538   struct opt_opt_t *opt;
00539 
00540   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00541   if (!opt)
00542     fatal("out of virtual memory");
00543 
00544   opt->name = name;
00545   opt->desc = desc;
00546   opt->nvars = 1;
00547   opt->nelt = NULL;
00548   opt->format = format ? format : "%12s";
00549   opt->oc = oc_enum;
00550   opt->variant.for_enum.var = var;
00551   opt->variant.for_enum.emap = emap;
00552   opt->variant.for_enum.eval = eval;
00553   opt->variant.for_enum.emap_sz = emap_sz;
00554   if (def_val)
00555     {
00556       if (!bind_to_enum(def_val, emap, eval, emap_sz, &enum_val))
00557         fatal("could not bind default value for option `%s'", name);
00558     }
00559   else
00560     enum_val = 0;
00561   opt->print = print;
00562   opt->accrue = FALSE;
00563 
00564   /* place on ODB's option list */
00565   opt->next = NULL;
00566   add_option(odb, opt);
00567 
00568   /* set default value */
00569   *var = enum_val;
00570 }
00571 
00572 /* register an enumeration option array, NOTE: all enumeration option variables
00573    must be of type `int', since true enum variables may be allocated with
00574    variable sizes by some compilers */
00575 void
00576 opt_reg_enum_list(struct opt_odb_t *odb,/* option data base */
00577                   char *name,           /* option name */
00578                   char *desc,           /* option description */
00579                   int *vars,            /* target array */
00580                   int nvars,            /* target array size */
00581                   int *nelt,            /* number of args parsed goes here */
00582                   char *def_val,        /* default variable value */
00583                   char **emap,          /* enumeration string map */
00584                   int *eval,            /* enumeration value map, optional */
00585                   int emap_sz,          /* size of maps */
00586                   int print,            /* print during `-dumpconfig'? */
00587                   char *format,         /* option value print format */
00588                   int accrue)           /* accrue list across uses */
00589 {
00590   int i, enum_val;
00591   struct opt_opt_t *opt;
00592 
00593   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00594   if (!opt)
00595     fatal("out of virtual memory");
00596 
00597   opt->name = name;
00598   opt->desc = desc;
00599   opt->nvars = nvars;
00600   opt->nelt = nelt;
00601   opt->format = format ? format : "%s";
00602   opt->oc = oc_enum;
00603   opt->variant.for_enum.var = vars;
00604   opt->variant.for_enum.emap = emap;
00605   opt->variant.for_enum.eval = eval;
00606   opt->variant.for_enum.emap_sz = emap_sz;
00607   if (def_val)
00608     {
00609       if (!bind_to_enum(def_val, emap, eval, emap_sz, &enum_val))
00610         fatal("could not bind default value for option `%s'", name);
00611     }
00612   else
00613     enum_val = 0;
00614   opt->print = print;
00615   opt->accrue = accrue;
00616 
00617   /* place on ODB's option list */
00618   opt->next = NULL;
00619   add_option(odb, opt);
00620 
00621   /* set default value */
00622   for (i=0; i < *nelt; i++)
00623     vars[i] = enum_val;
00624 }
00625 
00626 /* pre-defined boolean flag operands */
00627 #define NUM_FLAGS               28
00628 static char *flag_emap[NUM_FLAGS] = {
00629   "true", "t", "T", "True", "TRUE", "1", "y", "Y", "yes", "Yes", "YES",
00630   "on", "On", "ON",
00631   "false", "f", "F", "False", "FALSE", "0", "n", "N", "no", "No", "NO",
00632   "off", "Off", "OFF"
00633 };
00634 static int flag_eval[NUM_FLAGS] = {
00635   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00636   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00637 };
00638 
00639 /* register a boolean flag option variable */
00640 void
00641 opt_reg_flag(struct opt_odb_t *odb,     /* option data base */
00642              char *name,                /* option name */
00643              char *desc,                /* option description */
00644              int *var,                  /* target variable */
00645              int def_val,               /* default variable value */
00646              int print,                 /* print during `-dumpconfig'? */
00647              char *format)              /* optional value print format */
00648 {
00649   struct opt_opt_t *opt;
00650 
00651   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00652   if (!opt)
00653     fatal("out of virtual memory");
00654 
00655   opt->name = name;
00656   opt->desc = desc;
00657   opt->nvars = 1;
00658   opt->nelt = NULL;
00659   opt->format = format ? format : "%12s";
00660   opt->oc = oc_flag;
00661   opt->variant.for_enum.var = var;
00662   opt->variant.for_enum.emap = flag_emap;
00663   opt->variant.for_enum.eval = flag_eval;
00664   opt->variant.for_enum.emap_sz = NUM_FLAGS;
00665   opt->print = print;
00666   opt->accrue = FALSE;
00667 
00668   /* place on ODB's option list */
00669   opt->next = NULL;
00670   add_option(odb, opt);
00671 
00672   /* set default value */
00673   *var = def_val;
00674 }
00675 
00676 /* register a boolean flag option array */
00677 void
00678 opt_reg_flag_list(struct opt_odb_t *odb,/* option database */
00679                   char *name,           /* option name */
00680                   char *desc,           /* option description */
00681                   int *vars,            /* pointer to option array */
00682                   int nvars,            /* total entries in option array */
00683                   int *nelt,            /* number of elements parsed */
00684                   int *def_val,         /* default array value */
00685                   int print,            /* print during `-dumpconfig'? */
00686                   char *format,         /* optional value print format */
00687                   int accrue)           /* accrue list across uses */
00688 {
00689   int i;
00690   struct opt_opt_t *opt;
00691 
00692   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00693   if (!opt)
00694     fatal("out of virtual memory");
00695 
00696   opt->name = name;
00697   opt->desc = desc;
00698   opt->nvars = nvars;
00699   opt->nelt = nelt;
00700   opt->format = format ? format : "%s";
00701   opt->oc = oc_flag;
00702   opt->variant.for_enum.var = vars;
00703   opt->variant.for_enum.emap = flag_emap;
00704   opt->variant.for_enum.eval = flag_eval;
00705   opt->variant.for_enum.emap_sz = NUM_FLAGS;
00706   opt->print = print;
00707   opt->accrue = accrue;
00708 
00709   /* place on ODB's option list */
00710   opt->next = NULL;
00711   add_option(odb, opt);
00712 
00713   /* set default value */
00714   for (i=0; i < *nelt; i++)
00715     vars[i] = def_val[i];
00716 }
00717 
00718 /* register a string option variable */
00719 void
00720 opt_reg_string(struct opt_odb_t *odb,   /* option data base */
00721                char *name,              /* option name */
00722                char *desc,              /* option description */
00723                char **var,              /* pointer to string option variable */
00724                char *def_val,           /* default variable value */
00725                int print,               /* print during `-dumpconfig'? */
00726                char *format)            /* optional value print format */
00727 {
00728   struct opt_opt_t *opt;
00729 
00730   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00731   if (!opt)
00732     fatal("out of virtual memory");
00733 
00734   opt->name = name;
00735   opt->desc = desc;
00736   opt->nvars = 1;
00737   opt->nelt = NULL;
00738   opt->format = format ? format : "%12s";
00739   opt->oc = oc_string;
00740   opt->variant.for_string.var = var;
00741   opt->print = print;
00742   opt->accrue = FALSE;
00743 
00744   /* place on ODB's option list */
00745   opt->next = NULL;
00746   add_option(odb, opt);
00747 
00748   /* set default value */
00749   *var = def_val;
00750 }
00751 
00752 /* register a string option array */
00753 void
00754 opt_reg_string_list(struct opt_odb_t *odb,/* option data base */
00755                     char *name,         /* option name */
00756                     char *desc,         /* option description */
00757                     char **vars,        /* pointer to option string array */
00758                     int nvars,          /* target array size */
00759                     int *nelt,          /* number of args parsed goes here */
00760                     char **def_val,     /* default variable value */
00761                     int print,          /* print during `-dumpconfig'? */
00762                     char *format,       /* optional value print format */
00763                     int accrue)         /* accrue list across uses */
00764 {
00765   int i;
00766   struct opt_opt_t *opt;
00767 
00768   opt = (struct opt_opt_t *)calloc(1, sizeof(struct opt_opt_t));
00769   if (!opt)
00770     fatal("out of virtual memory");
00771 
00772   opt->name = name;
00773   opt->desc = desc;
00774   opt->nvars = nvars;
00775   opt->nelt = nelt;
00776   opt->format = format ? format : "%s";
00777   opt->oc = oc_string;
00778   opt->variant.for_string.var = vars;
00779   opt->print = print;
00780   opt->accrue = accrue;
00781 
00782   /* place on ODB's option list */
00783   opt->next = NULL;
00784   add_option(odb, opt);
00785 
00786   /* set default value */
00787   for (i=0; i < *nelt; i++)
00788     vars[i] = def_val[i];
00789 }
00790 
00791 /* process command line arguments, returns index of next argument to parse */
00792 int
00793 process_option(struct opt_odb_t *odb,   /* option database */
00794                int index,               /* index of the first arg to parse */
00795                int argc,                /* total number of arguments */
00796                char **argv)             /* argument string array */
00797 {
00798   int cnt, ent, nvars;
00799   char *endp;
00800   double tmp;
00801   struct opt_opt_t *opt;
00802 
00803   /* locate the option in the option database */
00804   for (opt=odb->options; opt != NULL; opt=opt->next)
00805     {
00806       if (!strcmp(opt->name, argv[index]))
00807         break;
00808     }
00809   if (!opt)
00810     {
00811       /* no one registered this option */
00812       fatal("option `%s' is undefined", argv[index]);
00813     }
00814   index++;
00815 
00816   /* process option arguments */
00817   switch (opt->oc)
00818     {
00819     case oc_int:
00820       /* this option needs at least one argument */
00821       if (index >= argc
00822           || (argv[index][0] == '-' && !isdigit((int)argv[index][1])))
00823         {
00824           /* no arguments available */
00825           fatal("option `%s' requires an argument", opt->name);
00826         }
00827       cnt = 0;
00828       if (opt->accrue)
00829         {
00830           ent = opt->nelt ? *opt->nelt : 0;
00831           nvars = 1;
00832           if (ent >= opt->nvars)
00833             fatal("too many invocations of option `%s'", opt->name);
00834         }
00835       else
00836         {
00837           ent = 0;
00838           if (opt->nelt)
00839             *opt->nelt = 0;
00840           nvars = opt->nvars;
00841         }
00842       /* parse all arguments */
00843       while (index < argc && cnt < nvars &&
00844              (argv[index][0] != '-' || isdigit((int)argv[index][1])))
00845         {
00846           opt->variant.for_int.var[ent] = strtol(argv[index], &endp, 0);
00847           if (*endp)
00848             {
00849               /* could not parse entire argument */
00850               fatal("could not parse argument `%s' of option `%s'",
00851                     argv[index], opt->name);
00852             }
00853           /* else, argument converted correctly */
00854           if (opt->nelt)
00855             (*opt->nelt)++;
00856           cnt++; index++; ent++;
00857         }
00858       break;
00859     case oc_uint:
00860       /* this option needs at least one argument */
00861       if (index >= argc || argv[index][0] == '-')
00862         {
00863           /* no arguments available */
00864           fatal("option `%s' requires an argument", opt->name);
00865         }
00866       cnt = 0;
00867       if (opt->accrue)
00868         {
00869           ent = opt->nelt ? *opt->nelt : 0;
00870           nvars = 1;
00871           if (ent >= opt->nvars)
00872             fatal("too many invocations of option `%s'", opt->name);
00873         }
00874       else
00875         {
00876           ent = 0;
00877           if (opt->nelt)
00878             *opt->nelt = 0;
00879           nvars = opt->nvars;
00880         }
00881       /* parse all arguments */
00882       while (index < argc && cnt < nvars && argv[index][0] != '-')
00883         {
00884           opt->variant.for_uint.var[ent] = strtoul(argv[index], &endp, 0);
00885           if (*endp)
00886             {
00887               /* could not parse entire argument */
00888               fatal("could not parse argument `%s' of option `%s'",
00889                     argv[index], opt->name);
00890             }
00891           /* else, argument converted correctly */
00892           if (opt->nelt)
00893             (*opt->nelt)++;
00894           cnt++; index++; ent++;
00895         }
00896       break;
00897     case oc_float:
00898       /* this option needs at least one argument */
00899       if (index >= argc
00900           || (argv[index][0] == '-' && !isdigit((int)argv[index][1])))
00901         {
00902           /* no arguments available */
00903           fatal("option `%s' requires an argument", opt->name);
00904         }
00905       cnt = 0;
00906       if (opt->accrue)
00907         {
00908           ent = opt->nelt ? *opt->nelt : 0;
00909           nvars = 1;
00910           if (ent >= opt->nvars)
00911             fatal("too many invocations of option `%s'", opt->name);
00912         }
00913       else
00914         {
00915           ent = 0;
00916           if (opt->nelt)
00917             *opt->nelt = 0;
00918           nvars = opt->nvars;
00919         }
00920       /* parse all arguments */
00921       while (index < argc && cnt < nvars &&
00922              (argv[index][0] != '-' || isdigit((int)argv[index][1])))
00923         {
00924           tmp = strtod(argv[index], &endp);
00925           if (*endp)
00926             {
00927               /* could not parse entire argument */
00928               fatal("could not parse argument `%s' of option `%s'",
00929                     argv[index], opt->name);
00930             }
00931           if (tmp < FLT_MIN || tmp > FLT_MAX)
00932             {
00933               /* over/underflow */
00934               fatal("FP over/underflow for argument `%s' of option `%s'",
00935                     argv[index], opt->name);
00936             }
00937           /* else, argument converted correctly */
00938           opt->variant.for_float.var[ent] = (float)tmp;
00939           if (opt->nelt)
00940             (*opt->nelt)++;
00941           cnt++; index++; ent++;
00942         }
00943       break;
00944     case oc_double:
00945       /* this option needs at least one argument */
00946       if (index >= argc
00947           || (argv[index][0] == '-' && !isdigit((int)argv[index][1])))
00948         {
00949           /* no arguments available */
00950           fatal("option `%s' requires an argument", opt->name);
00951         }
00952       cnt = 0;
00953       if (opt->accrue)
00954         {
00955           ent = opt->nelt ? *opt->nelt : 0;
00956           nvars = 1;
00957           if (ent >= opt->nvars)
00958             fatal("too many invocations of option `%s'", opt->name);
00959         }
00960       else
00961         {
00962           ent = 0;
00963           if (opt->nelt)
00964             *opt->nelt = 0;
00965           nvars = opt->nvars;
00966         }
00967       /* parse all arguments */
00968       while (index < argc && cnt < nvars &&
00969              (argv[index][0] != '-' || isdigit((int)argv[index][1])))
00970         {
00971           opt->variant.for_double.var[ent] = strtod(argv[index], &endp);
00972           if (*endp)
00973             {
00974               /* could not parse entire argument */
00975               fatal("could not parse argument `%s' of option `%s'",
00976                     argv[index], opt->name);
00977             }
00978           /* else, argument converted correctly */
00979           if (opt->nelt)
00980             (*opt->nelt)++;
00981           cnt++; index++; ent++;
00982         }
00983       break;
00984     case oc_enum:
00985       /* this option needs at least one argument */
00986       if (index >= argc || argv[index][0] == '-')
00987         {
00988           /* no arguments available */
00989           fatal("option `%s' requires an argument", opt->name);
00990         }
00991       cnt = 0;
00992       if (opt->accrue)
00993         {
00994           ent = opt->nelt ? *opt->nelt : 0;
00995           nvars = 1;
00996           if (ent >= opt->nvars)
00997             fatal("too many invocations of option `%s'", opt->name);
00998         }
00999       else
01000         {
01001           ent = 0;
01002           if (opt->nelt)
01003             *opt->nelt = 0;
01004           nvars = opt->nvars;
01005         }
01006       /* parse all arguments */
01007       while (index < argc && cnt < nvars && argv[index][0] != '-')
01008         {
01009           if (!bind_to_enum(argv[index],
01010                             opt->variant.for_enum.emap,
01011                             opt->variant.for_enum.eval,
01012                             opt->variant.for_enum.emap_sz,
01013                             &opt->variant.for_enum.var[ent]))
01014             {
01015               /* could not parse entire argument */
01016               fatal("could not parse argument `%s' of option `%s'",
01017                     argv[index], opt->name);
01018             }
01019           /* else, argument converted correctly */
01020           if (opt->nelt)
01021             (*opt->nelt)++;
01022           cnt++; index++; ent++;
01023         }
01024       break;
01025     case oc_flag:
01026       /* check if this option has at least one argument */
01027       if (index >= argc || argv[index][0] == '-')
01028         {
01029           /* no arguments available, default value for flag is true */
01030           opt->variant.for_enum.var[0] = TRUE;
01031           break;
01032         }
01033       /* else, parse boolean argument(s) */
01034       cnt = 0;
01035       if (opt->accrue)
01036         {
01037           ent = opt->nelt ? *opt->nelt : 0;
01038           nvars = 1;
01039           if (ent >= opt->nvars)
01040             fatal("too many invocations of option `%s'", opt->name);
01041         }
01042       else
01043         {
01044           ent = 0;
01045           if (opt->nelt)
01046             *opt->nelt = 0;
01047           nvars = opt->nvars;
01048         }
01049       while (index < argc && cnt < nvars && argv[index][0] != '-')
01050         {
01051           if (!bind_to_enum(argv[index],
01052                             opt->variant.for_enum.emap,
01053                             opt->variant.for_enum.eval,
01054                             opt->variant.for_enum.emap_sz,
01055                             &opt->variant.for_enum.var[ent]))
01056             {
01057               /* could not parse entire argument, default to true */
01058               opt->variant.for_enum.var[ent] = TRUE;
01059               break;
01060             }
01061           else
01062             {
01063               /* else, argument converted correctly */
01064               if (opt->nelt)
01065                 (*opt->nelt)++;
01066               cnt++; index++; ent++;
01067             }
01068         }
01069       break;
01070     case oc_string:
01071       /* this option needs at least one argument */
01072       if (index >= argc || argv[index][0] == '-')
01073         {
01074           /* no arguments available */
01075           fatal("option `%s' requires an argument", opt->name);
01076         }
01077       cnt = 0;
01078       if (opt->accrue)
01079         {
01080           ent = opt->nelt ? *opt->nelt : 0;
01081           nvars = 1;
01082           if (ent >= opt->nvars)
01083             fatal("too many invocations of option `%s'", opt->name);
01084         }
01085       else
01086         {
01087           ent = 0;
01088           if (opt->nelt)
01089             *opt->nelt = 0;
01090           nvars = opt->nvars;
01091         }
01092       /* parse all arguments */
01093       while (index < argc && cnt < nvars && argv[index][0] != '-')
01094         {
01095           opt->variant.for_string.var[ent] = argv[index];
01096           if (opt->nelt)
01097             (*opt->nelt)++;
01098           cnt++; index++; ent++;
01099         }
01100       break;
01101     default:
01102       panic("bogus option class");
01103     }
01104 
01105   return index;
01106 }
01107 
01108 /* forward declarations */
01109 static void process_file(struct opt_odb_t *odb, char *fname, int depth);
01110 static void dump_config(struct opt_odb_t *odb, char *fname);
01111 
01112 /* process a command line, internal version that tracks `-config' depth */
01113 static void
01114 __opt_process_options(struct opt_odb_t *odb,    /* option data base */
01115                       int argc,                 /* number of arguments */
01116                       char **argv,              /* argument array */
01117                       int depth)                /* `-config' option depth */
01118 {
01119   int index, do_dumpconfig;
01120   char *dumpconfig_name;
01121 
01122   index = 0;
01123   do_dumpconfig = FALSE;
01124   dumpconfig_name = NULL;
01125   /* visit all command line arguments */
01126   while (index < argc)
01127     {
01128       /* process any encountered orphans */
01129       while (index < argc && argv[index][0] != '-')
01130         {
01131           if (depth > 0)
01132             {
01133               /* orphans are not allowed during config file processing */
01134               fatal("orphan `%s' encountered during config file processing",
01135                     argv[index]);
01136             }
01137           /* else, call the user-stalled orphan handler */
01138           if (odb->orphan_fn)
01139             {
01140               if (!odb->orphan_fn(index+1, argc, argv))
01141                 {
01142                   /* done processing command line */
01143                   goto done_processing;
01144                 }
01145             }
01146           else
01147             {
01148               /* no one claimed this option */
01149               fatal("orphan argument `%s' was unclaimed", argv[index]);
01150             }
01151           /* go to next option */
01152         }
01153 
01154       /* done with command line? */
01155       if (index == argc)
01156         {
01157           /* done processing command line */
01158           goto done_processing;
01159         }
01160       /* when finished, argv[index] is an option to parse */
01161 
01162       /* process builtin options */
01163       if (!strcmp(argv[index], "-config"))
01164         {
01165           /* handle `-config' builtin option */
01166           index++;
01167           if (index >= argc || argv[index][0] == '-')
01168             {
01169               /* no arguments available */
01170               fatal("option `-config' requires an argument");
01171             }
01172           process_file(odb, argv[index], depth);
01173           index++;
01174         }
01175       else if (!strcmp(argv[index], "-dumpconfig"))
01176         {
01177           /* this is performed *last* */
01178           do_dumpconfig = TRUE;
01179           /* handle `-dumpconfig' builtin option */
01180           index++;
01181           if (index >= argc
01182               || (argv[index][0] == '-' && argv[index][1] != '\0'))
01183             {
01184               /* no arguments available */
01185               fatal("option `-dumpconfig' requires an argument");
01186             }
01187           dumpconfig_name = argv[index];
01188           index++;
01189         }
01190       else
01191         {
01192           /* process user-installed option */
01193           index = process_option(odb, index, argc, argv);
01194         }
01195     }
01196  done_processing:
01197 
01198   if (do_dumpconfig)
01199     dump_config(odb, dumpconfig_name);
01200 }
01201 
01202 /* process command line arguments */
01203 void
01204 opt_process_options(struct opt_odb_t *odb,      /* option data base */
01205                     int argc,                   /* number of arguments */
01206                     char **argv)                /* argument array */
01207 {
01208   /* need at least two entries to have an option */
01209   if (argc < 2)
01210     return;
01211 
01212   /* process the command, starting at `-config' depth zero */
01213   __opt_process_options(odb, argc-1, argv+1, /* top level */0);
01214 }
01215 
01216 /* handle `-config' builtin option */
01217 #define MAX_LINE_ARGS           256
01218 #define MAX_FILENAME_LEN        1024
01219 static void
01220 process_file(struct opt_odb_t *odb, char *fname, int depth)
01221 {
01222   int largc;
01223   char *largv[MAX_LINE_ARGS];
01224   char line[1024], *p, *q;
01225   char cwd[MAX_FILENAME_LEN];
01226   char *header;
01227   FILE *fd;
01228 
01229   fd = fopen(fname, "r");
01230   if (!fd)
01231     fatal("could not open configuration file `%s'", fname);
01232 
01233   if (!getcwd(cwd, MAX_FILENAME_LEN))
01234     fatal("can't get cwd");
01235 
01236   header = strrchr(fname, '/');
01237   if (header != NULL)
01238     {
01239       /* filename is path - get header */
01240       *header = '\0';
01241       if (chdir(fname) == -1)
01242         fatal("can't chdir to %s\n", fname);
01243       *header = '/';
01244     }
01245 
01246   while (!feof(fd))
01247     {
01248 #if 0
01249       fprintf(stderr, "!feof(fd): %d, strlen(line): %d, line: %s\n",
01250               !feof(fd), strlen(line), line);
01251 #endif
01252 
01253       line[0] = '\n';
01254       /* read a line from the file and chop */
01255       fgets(line, 1024, fd);
01256       if (line[0] == '\0' || line[0] == '\n')
01257         continue;
01258       if (line[strlen(line)-1] == '\n')
01259         line[strlen(line)-1] = '\0';
01260 
01261       /* process one line from the file */
01262       largc = 0; p = line;
01263       while (*p)
01264         {
01265           /* skip whitespace */
01266           while (*p != '\0' && (*p == ' ' || *p == '\t'))
01267             p++;
01268 
01269           /* ignore empty lines and comments */
01270           if (*p == '\0' || *p == '#')
01271             break;
01272 
01273           /* skip to the end of the argument */
01274           q = p;
01275           while (*q != '\0' && *q != ' ' && *q != '\t')
01276             q++;
01277           if (*q)
01278             {
01279               *q = '\0';
01280               q++;
01281             }
01282 
01283           /* marshall an option array */
01284           largv[largc++] = mystrdup(p);
01285 
01286           if (largc == MAX_LINE_ARGS)
01287             {
01288               if (chdir(cwd) == -1)
01289                 fatal("can't chdir back to %s\n", cwd);
01290               fatal("option line too complex in file `%s'", fname);
01291             }
01292 
01293           /* go to next argument */
01294           p = q;
01295         }
01296 
01297       /* process the line */
01298       if (largc > 0)
01299         __opt_process_options(odb, largc, largv, depth+1);
01300       /* else, empty line */
01301     }
01302 
01303   fclose(fd);
01304 
01305   if (chdir(cwd) == -1)
01306     fatal("can't chdir back to %s\n", cwd);
01307 }
01308 
01309 /* print the value of an option */
01310 void
01311 opt_print_option(struct opt_opt_t *opt,/* option variable */
01312                  FILE *fd)              /* output stream */
01313 {
01314   int i, nelt;
01315 
01316   switch (opt->oc)
01317     {
01318     case oc_int:
01319       if (opt->nelt)
01320         nelt = *(opt->nelt);
01321       else
01322         nelt = 1;
01323       for (i=0; i<nelt; i++)
01324         {
01325           fprintf(fd, opt->format, opt->variant.for_int.var[i]);
01326           fprintf(fd, " ");
01327         }
01328       break;
01329     case oc_uint:
01330       if (opt->nelt)
01331         nelt = *(opt->nelt);
01332       else
01333         nelt = 1;
01334       for (i=0; i<nelt; i++)
01335         {
01336           fprintf(fd, opt->format, opt->variant.for_uint.var[i]);
01337           fprintf(fd, " ");
01338         }
01339       break;
01340     case oc_float:
01341       if (opt->nelt)
01342         nelt = *(opt->nelt);
01343       else
01344         nelt = 1;
01345       for (i=0; i<nelt; i++)
01346         {
01347           fprintf(fd, opt->format, (double)opt->variant.for_float.var[i]);
01348           fprintf(fd, " ");
01349         }
01350       break;
01351     case oc_double:
01352       if (opt->nelt)
01353         nelt = *(opt->nelt);
01354       else
01355         nelt = 1;
01356       for (i=0; i<nelt; i++)
01357         {
01358           fprintf(fd, opt->format, opt->variant.for_double.var[i]);
01359           fprintf(fd, " ");
01360         }
01361       break;
01362     case oc_enum:
01363       if (opt->nelt)
01364         nelt = *(opt->nelt);
01365       else
01366         nelt = 1;
01367       for (i=0; i<nelt; i++)
01368         {
01369           char *estr = bind_to_str(opt->variant.for_enum.var[i],
01370                                    opt->variant.for_enum.emap,
01371                                    opt->variant.for_enum.eval,
01372                                    opt->variant.for_enum.emap_sz);
01373           if (!estr)
01374             panic("could not bind enum `%d' for option `%s'",
01375                   opt->variant.for_enum.var[i], opt->name);
01376 
01377           fprintf(fd, opt->format, estr);
01378           fprintf(fd, " ");
01379         }
01380       break;
01381     case oc_flag:
01382       if (opt->nelt)
01383         nelt = *(opt->nelt);
01384       else
01385         nelt = 1;
01386       for (i=0; i<nelt; i++)
01387         {
01388           char *estr = bind_to_str(opt->variant.for_enum.var[i],
01389                                    opt->variant.for_enum.emap,
01390                                    opt->variant.for_enum.eval,
01391                                    opt->variant.for_enum.emap_sz);
01392           if (!estr)
01393             panic("could not bind boolean `%d' for option `%s'",
01394                   opt->variant.for_enum.var[i], opt->name);
01395           
01396           fprintf(fd, opt->format, estr);
01397           fprintf(fd, " ");
01398         }
01399       break;
01400     case oc_string:
01401       if (!opt->nvars)
01402         {
01403           fprintf(fd, "%12s ", "<null>");
01404           break;
01405         }
01406       if (opt->nelt)
01407         nelt = *(opt->nelt);
01408       else
01409         nelt = 1;
01410       if (nelt == 0)
01411         {
01412           fprintf(fd, "%12s ", "<null>");
01413           break;
01414         }
01415       else
01416         {
01417           for (i=0; i<nelt; i++)
01418             {
01419               fprintf(fd, opt->format,
01420                       (opt->variant.for_string.var[i]
01421                        ? opt->variant.for_string.var[i]
01422                        : "<null>"));
01423               fprintf(fd, " ");
01424             }
01425         }
01426       break;
01427     default:
01428       panic("bogus option class");
01429     }
01430 }
01431 
01432 /* print any options header */
01433 static void
01434 print_option_header(struct opt_odb_t *odb,/* options database */
01435                     FILE *fd)           /* output stream */
01436 {
01437   if (!odb->header)
01438     return;
01439 
01440   fprintf(fd, "\n%s\n", odb->header);
01441 }
01442 
01443 /* print option notes */
01444 static void
01445 print_option_notes(struct opt_odb_t *odb,/* options database */
01446                    FILE *fd)            /* output stream */
01447 {
01448   struct opt_note_t *note;
01449 
01450   if (!odb->notes)
01451     return;
01452 
01453   fprintf(fd, "\n");
01454   for (note=odb->notes; note != NULL; note=note->next)
01455     fprintf(fd, "%s\n", note->note);
01456   fprintf(fd, "\n");
01457 }
01458 
01459 /* builtin options */
01460 static struct opt_opt_t dumpconfig_opt =
01461   { NULL, "-dumpconfig", "dump configuration to a file",
01462     0, NULL, NULL, FALSE, FALSE, oc_string };
01463 static struct opt_opt_t config_opt =
01464   { &dumpconfig_opt, "-config", "load configuration from a file",
01465     0, NULL, NULL, FALSE, FALSE, oc_string };
01466 static struct opt_opt_t *builtin_options = &config_opt;
01467 
01468 /* return non-zero if the option is a NULL-valued string option */
01469 int                                     /* non-zero if null string option */
01470 opt_null_string(struct opt_opt_t *opt)
01471 {
01472   return (opt != NULL
01473           && opt->oc == oc_string
01474           && (opt->nvars == 0
01475               || (opt->nelt != NULL && *opt->nelt == 0)
01476               || (opt->nelt == NULL
01477                   && (opt->variant.for_string.var == NULL
01478                       || opt->variant.for_string.var[0] == NULL))));
01479 }
01480 
01481 /* print all options and current values */
01482 void
01483 opt_print_options(struct opt_odb_t *odb,/* option data base */
01484                   FILE *fd,             /* output stream */
01485                   int terse,            /* print terse options? */
01486                   int notes)            /* include notes? */
01487 {
01488   struct opt_opt_t *opt;
01489 
01490   if (!odb)
01491     {
01492       /* no options */
01493       return;
01494     }
01495 
01496   /* print any options header */
01497   if (notes)
01498     print_option_header(odb, fd);
01499 
01500   /* dump out builtin options */
01501   for (opt=builtin_options; opt != NULL; opt=opt->next)
01502     {
01503       if (terse)
01504         fprintf(fd, "# %-27s # %s\n", opt->name, opt->desc);
01505       else
01506         {
01507           fprintf(fd, "# %s\n", opt->desc);
01508           fprintf(fd, "# %-22s\n\n", opt->name);
01509         }
01510     }
01511 
01512   /* dump out options from options database */
01513   for (opt=odb->options; opt != NULL; opt=opt->next)
01514     {
01515       if (terse)
01516         {
01517           if (!opt->print || opt_null_string(opt))
01518               fprintf(fd, "# %-14s ", opt->name);
01519           else
01520             fprintf(fd, "%-16s ", opt->name);
01521           opt_print_option(opt, fd);
01522           if (opt->desc)
01523             fprintf(fd, "# %-22s", opt->desc);
01524           fprintf(fd, "\n");
01525         }
01526       else
01527         {
01528           if (opt->desc)
01529             fprintf(fd, "# %s\n", opt->desc);
01530           if (!opt->print || opt_null_string(opt))
01531             fprintf(fd, "# %-20s ", opt->name);
01532           else
01533             fprintf(fd, "%-22s ", opt->name);
01534           opt_print_option(opt, fd);
01535           fprintf(fd, "\n\n");
01536         }
01537     }
01538 
01539   /* print option notes */
01540   if (notes)
01541     print_option_notes(odb, fd);
01542 }
01543 
01544 /* print help information for an option */
01545 static void
01546 print_help(struct opt_opt_t *opt,       /* option variable */
01547            FILE *fd)                    /* output stream */
01548 {
01549   char *s = NULL;
01550 
01551   fprintf(fd, "%-16s ", opt->name);
01552   switch (opt->oc)
01553     {
01554     case oc_int:
01555       if (opt->nvars == 1)
01556         s = "<int>";
01557       else
01558         s = "<int list...>";
01559       break;
01560     case oc_uint:
01561       if (opt->nvars == 1)
01562         s = "<uint>";
01563       else
01564         s = "<uint list...>";
01565       break;
01566     case oc_float:
01567       if (opt->nvars == 1)
01568         s = "<float>";
01569       else
01570         s = "<float list...>";
01571       break;
01572     case oc_double:
01573       if (opt->nvars == 1)
01574         s = "<double>";
01575       else
01576         s = "<double list...>";
01577       break;
01578     case oc_enum:
01579       if (opt->nvars == 1)
01580         s = "<enum>";
01581       else
01582         s = "<enum list...>";
01583       break;
01584     case oc_flag:
01585       if (opt->nvars == 1)
01586         s = "<true|false>";
01587       else
01588         s = "<true|false list...>";
01589       break;
01590     case oc_string:
01591       if (opt->nvars == 0 || opt->nvars == 1)
01592         s = "<string>";
01593       else
01594         s = "<string list...>";
01595       break;
01596     default:
01597       panic("bogus option class");
01598     }
01599   fprintf(fd, "%-16s # ", s);
01600   opt_print_option(opt, fd);
01601   fprintf(fd, "# %-22s\n", opt->desc);
01602 }
01603 
01604 /* print option help page with default values */
01605 void
01606 opt_print_help(struct opt_odb_t *odb,   /* option data base */
01607                FILE *fd)                /* output stream */
01608 {
01609   struct opt_opt_t *opt;
01610 
01611   /* print any options header */
01612   print_option_header(odb, fd);
01613 
01614   fprintf(fd, "#\n");
01615   fprintf(fd, "%-16s %-16s # %12s # %-22s\n",
01616           "# -option", "<args>", "<default>", "description");
01617   fprintf(fd, "#\n");
01618 
01619   /* print out help info for builtin options */
01620   for (opt=builtin_options; opt != NULL; opt=opt->next)
01621     print_help(opt, fd);
01622 
01623   /* print out help info for options in options database */
01624   for (opt=odb->options; opt != NULL; opt=opt->next)
01625     print_help(opt, fd);
01626 
01627   /* print option notes */
01628   print_option_notes(odb, fd);
01629 }
01630 
01631 /* handle `-dumpconfig' builtin option, print options from file argument */
01632 static void
01633 dump_config(struct opt_odb_t *odb,      /* option data base */
01634             char *fname)                /* output file name, "-" == stdout */
01635 {
01636   FILE *fd;
01637 
01638   /* open output file stream */
01639   if (!strcmp(fname, "-"))
01640     fd = stderr;
01641   else
01642     {
01643       fd = fopen(fname, "w");
01644       if (!fd)
01645         fatal("could not open file `%s'", fname);
01646     }
01647 
01648   /* print current option values to output stream */
01649   opt_print_options(odb, fd, /* long */FALSE, /* !notes */FALSE);
01650 
01651   /* close output stream, if not a standard stream */
01652   if (fd != stdout && fd != stderr)
01653     fclose(fd);
01654 }
01655 
01656 /* find an option by name in the option database, returns NULL if not found */
01657 struct opt_opt_t *
01658 opt_find_option(struct opt_odb_t *odb,  /* option database */
01659                 char *opt_name) /* option name */
01660 {
01661   struct opt_opt_t *opt;
01662 
01663   /* search builtin options */
01664   for (opt = builtin_options; opt != NULL; opt = opt->next)
01665     {
01666       if (!strcmp(opt->name, opt_name))
01667         {
01668           /* located option */
01669           return opt;
01670         }
01671     }
01672 
01673   /* search user-installed options */
01674   for (opt = odb->options; opt != NULL; opt = opt->next)
01675     {
01676       if (!strcmp(opt->name, opt_name))
01677         {
01678           /* located option */
01679           return opt;
01680         }
01681     }
01682   /* not found */
01683   return NULL;
01684 }
01685 
01686 /* register an options header, the header is printed before the option list */
01687 void
01688 opt_reg_header(struct opt_odb_t *odb,   /* option database */
01689                char *header)            /* options header string */
01690 {
01691   odb->header = header;
01692 }
01693 
01694 /* register an option note, notes are printed after the list of options */
01695 void
01696 opt_reg_note(struct opt_odb_t *odb,     /* option database */
01697              char *note_str)            /* option note */
01698 {
01699   struct opt_note_t *note, *elt, *prev;
01700 
01701   note = (struct opt_note_t *)calloc(1, sizeof(struct opt_note_t));
01702   if (!note)
01703     fatal("out of virtual memory");
01704 
01705   /* record note */
01706   note->next = NULL;
01707   note->note = note_str;
01708 
01709   /* add to end of option notes list */
01710   for (prev=NULL, elt=odb->notes; elt != NULL; prev=elt, elt=elt->next)
01711     /* nada */;
01712 
01713   if (prev != NULL)
01714     prev->next = note;
01715   else /* prev == NULL */
01716     odb->notes = note;
01717   note->next = NULL;
01718 }
01719 
01720 
01721 #ifdef TEST
01722 
01723 int
01724 f_orphan_fn(int i, int argc, char **argv)
01725 {
01726   fprintf(stdout, "orphans detected at index %d, arg = `%s'...\n", i, argv[i]);
01727 
01728   /* done processing */
01729   return FALSE;
01730 }
01731 
01732 #define MAX_VARS 4
01733 void
01734 main(int argc, char **argv)
01735 {
01736   struct opt_odb_t *odb;
01737 
01738   int n_int_vars, n_uint_vars, n_float_vars, n_double_vars;
01739   int n_enum_vars, n_enum_eval_vars, n_flag_vars, n_string_vars;
01740   int int_var, int_vars[MAX_VARS];
01741   unsigned int uint_var, uint_vars[MAX_VARS];
01742   float float_var, float_vars[MAX_VARS];
01743   double double_var, double_vars[MAX_VARS];
01744   int flag_var, flag_vars[MAX_VARS];
01745   char *string_var, *string_vars[MAX_VARS];
01746 
01747   enum etest_t { enum_a, enum_b, enum_c, enum_d, enum_NUM };
01748   static char *enum_emap[enum_NUM] =
01749     { "enum_a", "enum_b", "enum_c", "enum_d" };
01750   static int enum_eval[enum_NUM] =
01751     { enum_d, enum_c, enum_b, enum_a };
01752   int enum_var, enum_vars[MAX_VARS];
01753   int enum_eval_var, enum_eval_vars[MAX_VARS];
01754 
01755   /* get an options processor */
01756   odb = opt_new(f_orphan_fn);
01757 
01758 
01759   opt_reg_int(odb, "-opt:int", "This is an integer option.",
01760               &int_var, 1, /* print */TRUE, /* default format */NULL);
01761   opt_reg_int_list(odb, "-opt:int:list", "This is an integer list option.",
01762                    int_vars, MAX_VARS, &n_int_vars, 2,
01763                    /* print */TRUE, /* default format */NULL);
01764   opt_reg_uint(odb, "-opt:uint", "This is an unsigned integer option.",
01765                &uint_var, 3, /* print */TRUE, /* default format */NULL);
01766   opt_reg_uint_list(odb, "-opt:uint:list",
01767                     "This is an unsigned integer list option.",
01768                     uint_vars, MAX_VARS, &n_uint_vars, 4,
01769                     /* print */TRUE, /* default format */NULL);
01770   opt_reg_float(odb, "-opt:float", "This is a float option.",
01771                 &float_var, 5.0, /* print */TRUE, /* default format */NULL);
01772   opt_reg_float_list(odb, "-opt:float:list", "This is a float list option.",
01773                      float_vars, MAX_VARS, &n_float_vars, 6.0,
01774                      /* print */TRUE, /* default format */NULL);
01775   opt_reg_double(odb, "-opt:double", "This is a double option.",
01776                  &double_var, 7.0, /* print */TRUE, /* default format */NULL);
01777   opt_reg_double_list(odb, "-opt:double:list", "This is a double list option.",
01778                       double_vars, MAX_VARS, &n_double_vars, 8.0,
01779                       /* print */TRUE, /* default format */NULL);
01780   opt_reg_enum(odb, "-opt:enum", "This is an enumeration option.",
01781                &enum_var, "enum_a", enum_emap, /* index map */NULL, enum_NUM,
01782                /* print */TRUE, /* default format */NULL);
01783   opt_reg_enum_list(odb, "-opt:enum:list", "This is a enum list option.",
01784                     enum_vars, MAX_VARS, &n_enum_vars, "enum_b",
01785                     enum_emap, /* index map */NULL, enum_NUM,
01786                     /* print */TRUE, /* default format */NULL);
01787   opt_reg_enum(odb, "-opt:enum:eval", "This is an enumeration option w/eval.",
01788                &enum_eval_var, "enum_b", enum_emap, enum_eval, enum_NUM,
01789                /* print */TRUE, /* default format */NULL);
01790   opt_reg_enum_list(odb, "-opt:enum:eval:list",
01791                     "This is a enum list option w/eval.",
01792                     enum_eval_vars, MAX_VARS, &n_enum_eval_vars, "enum_a",
01793                     enum_emap, enum_eval, enum_NUM,
01794                     /* print */TRUE, /* default format */NULL);
01795   opt_reg_flag(odb, "-opt:flag", "This is a boolean flag option.",
01796                &flag_var, FALSE, /* print */TRUE, /* default format */NULL);
01797   opt_reg_flag_list(odb, "-opt:flag:list",
01798                     "This is a boolean flag list option.",
01799                     flag_vars, MAX_VARS, &n_flag_vars, TRUE,
01800                     /* print */TRUE, /* default format */NULL);
01801   opt_reg_string(odb, "-opt:string", "This is a string option.",
01802                  &string_var, "a:string",
01803                  /* print */TRUE, /* default format */NULL);
01804   opt_reg_string_list(odb, "-opt:string:list", "This is a string list option.",
01805                     string_vars, MAX_VARS, &n_string_vars, "another:string",
01806                     /* print */TRUE, /* default format */NULL);
01807 
01808   /* parse options */
01809   opt_process_options(odb, argc, argv);
01810 
01811   /* print options */
01812   fprintf(stdout, "## Current Option Values ##\n");
01813   opt_print_options(odb, stdout, /* long */FALSE, /* notes */TRUE);
01814 
01815   /* all done */
01816   opt_delete(odb);
01817   exit(0);
01818 }
01819 
01820 #endif /* TEST */


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214