• Main Page
  • Classes
  • Files
  • File List
  • File Members

par.c

Go to the documentation of this file.
00001 #include "copyright.h"
00002 /*============================================================================*/
00003 /*! \file par.c
00004  *  \brief Set of routines to provide simple access to a R/O parameter file
00005  *
00006  * PURPOSE:  set of routines to provide simple access to a R/O parameter file
00007  *   slightly modeled after FORTRAN namelist.  Parameters can also be read
00008  *   directly from the commandline in the same format.
00009  *
00010  * EXAMPLE of input file in 'par' format:
00011  * -     <blockname1>      # block name; should be on a line by itself
00012  * -     name1 = value1    # whitespace around the = is optional
00013  * -                       # blank lines between blocks are OK
00014  * -     <blockname2>      # start new block
00015  * -     name1 = value1    # note that name1 can appear in different blocks
00016  * -     name2 = value2    #
00017  * -
00018  * -     <blockname1>      # same blockname can re-appear, though is a bit odd
00019  * -     name3 = value3    # this would be the 3rd name in this block
00020  *
00021  * LIMITATIONS:
00022  *   - MAXLEN means static strings; could make fancier dynamic string reader
00023  *   - blocknames and parameters (key=val#comment) are all single-line based
00024  *
00025  * HISTORY:
00026  * - 15-nov-2002  Created for the Athena/Cambridge release 1.0 -- Peter Teuben
00027  * - 18-nov-2002  added par_cmdline()                               -- PJT
00028  * - 6-jan-2003   made the public par_getX() routines               -- PJT
00029  * - 6-jan-2003   Implemented par_setX() routines -- Thomas A. Gardiner
00030  * - 7-jan-2003   add_block() find or add a named block             -- TAG
00031  * - 7-jan-2003   add_par() split into add_par() and add_par_line() -- TAG
00032  * - 7-jan-2003   mode = 0, par_dump() outputs the comment field    -- TAG
00033  * - 9-jan-2003   add_par() only overwrites a comment field in an 
00034  *                    existing par if the input comment is != NULL. -- TAG
00035  * - 9-jan-2003   Column aligned format added to mode=0, par_dump() -- TAG
00036  * - 1-mar-2004   Moved error out to utils.c as ath_error()         -- PJT
00037  * - 2-apr-2004   Added the get_par_def routines                    -- PJT
00038  *
00039  * CONTAINS PUBLIC FUNCTIONS:
00040  * - int par_open()        - open and read a parameter file for R/O access
00041  * - void par_cmdline()    - parse a commandline, extract parameters
00042  * - int par_exist()       - returns 0 if block/name exists
00043  * - char *par_gets()      - returns a string from input field
00044  * - int par_geti()        - returns an integer from the input field
00045  * - double par_getd()     - returns a Real from the input field
00046  * - char *par_gets_def()  - set string to input value, or default
00047  * - int par_geti_def()    - set int to input value, or default
00048  * - double par_getd_def() - set double to input value, or default
00049  * - void par_sets()       - sets/adds a string
00050  * - void par_seti()       - sets/adds an integer
00051  * - void par_setd()       - sets/adds a Real
00052  * - void par_dump()       - print out all Blocks/Pars for debugging
00053  * - void par_close()      - free memory
00054  * - void par_dist_mpi()   - broadcast Blocks and Pars to children in MPI 
00055  *
00056  * VARIABLE TYPE AND STRUCTURE DEFINITIONS:
00057  * - Par_s   - linked list of parameters
00058  * - Block_s - linked list of Pars                                            
00059  *
00060  * PRIVATE FUNCTION PROTOTYPES: 
00061  * - allocate()       - wrapper for calloc which terminates code on failure
00062  * - my_strdup()      - wrapper for strdup which terminates code on failure
00063  * - skipwhite()      - returns pointer to next non-whitespace
00064  * - str_term()       - remove whitespace at end of string
00065  * - line_block_name()- extract block name
00066  * - add_par()        - add "name = value # comment" to Par list
00067  * - add_par_line()   - parse line and add it to a block
00068  * - add_block()      - find or add a new named block
00069  * - find_block()     - check if a Block name already exists
00070  * - find_par()       - check if a Block contains a Par with certain name
00071  * - free_all         - free all Blocks/Pars
00072  * - par_getsl        - return string, for use of local functions only
00073  * - par_debug()      - sets debug level in test program
00074  * - main()           - test program for par package
00075  *                                                                            */
00076 /*============================================================================*/
00077 
00078 #include <stdio.h>
00079 #include <stdlib.h>
00080 #include <string.h>
00081 #include <stdarg.h>
00082 #include <ctype.h>
00083 #include "defs.h"
00084 #include "prototypes.h"
00085 
00086 static int  now_open = 0;         /* keep track of status of the par routines */
00087 static char *now_filename = NULL; /* keep pointer to last open filename */
00088 
00089 /*! \struct Par
00090  *  \brief Holds a single name=value#comment tuple as a linked list */
00091 typedef struct Par_s {   
00092   char *name;                 /* name of the parameter */
00093   char *value;                /* (string) value of the parameter */
00094   char *comment;              /* space for comment */
00095   struct Par_s *next;         /* pointer to the next parameter */
00096 } Par;
00097 
00098 /*! \struct Block
00099  *  \brief  Linked list of Pars that belong together */
00100 typedef struct Block_s { 
00101   char *name;                 /* name of this block */
00102   Par  *p;                    /* first member of list in this block */
00103   int max_name_len;           /* length of longest name  in Par list */
00104   int max_value_len;          /* length of longest value in Par list */
00105   struct Block_s *next;       /* pointer to next block */
00106 } Block;
00107 
00108 /*! \typedef void (*proc)(void)
00109  *  \brief function pointer type */
00110 typedef void (*proc)(void);        /* function pointer type */
00111 static Block *base_block = NULL;   /* base of all Block's that contain Par's  */
00112 static int debug = 0;              /* debug level, set to 1 for debug output  */
00113 
00114 /*==============================================================================
00115  * PRIVATE FUNCTION PROTOTYPES: 
00116  *   allocate()       - wrapper for calloc which terminates code on failure
00117  *   my_strdup()      - wrapper for strdup which terminates code on failure
00118  *   skipwhite()      - returns pointer to next non-whitespace
00119  *   str_term()       - remove whitespace at end of string
00120  *   line_block_name()- extract block name
00121  *   add_par()        - add "name = value # comment" to Par list
00122  *   add_par_line()   - parse line and add it to a block
00123  *   add_block()      - find or add a new named block
00124  *   find_block()     - check if a Block name already exists
00125  *   find_par()       - check if a Block contains a Par with certain name
00126  *   free_all         - free all Blocks/Pars
00127  *   par_getsl        - return string, for use of local functions only
00128  *   par_debug()      - sets debug level in test program
00129  *   main()           - test program for par package
00130  *============================================================================*/
00131 
00132 static void *allocate(size_t size);
00133 static char *my_strdup(char *in);
00134 static char *skipwhite(char *cp);
00135 static void str_term(char *cp);
00136 static char *line_block_name(char *line);
00137 static void add_par(Block *bp, char *name, char *value, char *comment);
00138 static void add_par_line(Block *bp, char *line);
00139 static Block *add_block(char *name);
00140 static Block *find_block(char *name);
00141 static Par *find_par(Block *bp, char *name);
00142 static void free_all(void);
00143 static char *par_getsl(char *block, char *name);
00144 void par_debug(int level);
00145 
00146 /*=========================== PUBLIC FUNCTIONS ===============================*/
00147 /*----------------------------------------------------------------------------*/
00148 /*! \fn  void par_open(char *filename)
00149  *  \brief Open a parameter file for R/O access.  
00150  *
00151  *  Lines read from the file
00152  *   are locally patched; all names, values and comments are allocated and put
00153  *   into a linked list of Block's and Par's.
00154  */
00155 
00156 void par_open(char *filename)
00157 {
00158   FILE *fp;
00159   char line[MAXLEN];
00160   char *block_name, *cp;
00161   Block *bp = NULL;
00162 
00163   if (now_open) ath_error("Parameter file %s still open\n",now_filename);
00164   if (now_filename) free(now_filename);
00165   fp = fopen(filename,"r");
00166   if (fp == NULL) 
00167     ath_error("Parameter file %s could not be opened, try -i PARFILE\n"
00168       ,filename);
00169   if (debug) fprintf(stdout,"Opening \"%s\" for parameter access\n",filename);
00170   now_open = 1;
00171   now_filename = my_strdup(filename);
00172 
00173   while (fgets(line,MAXLEN,fp)) {      /* dumb approach: one line per command */
00174     cp = skipwhite(line);              /* skip whitespace first */
00175     if (*cp == '\0') continue;         /* blank line */
00176     if (*cp == '#') continue;          /* skip comments */
00177     if (strncmp(cp,"<par_end>",9) == 0) break; /* end of parameter file */
00178     if (*cp == '<') {                   /* a new Block */
00179       block_name = line_block_name(cp); /* extract name from <name> */
00180       bp = add_block(block_name);       /* find or add a block with this name */
00181       continue;
00182     }
00183     add_par_line(bp,cp);                /* add par to this block */
00184   }
00185   fclose(fp);
00186   return;
00187 }
00188 
00189 /*----------------------------------------------------------------------------*/
00190 /*! \fn void par_cmdline(int argc, char *argv[]) 
00191  *  \brief Parse a commandline, very forgiving (no warnings) when not in
00192  *   the right block/name=value format */
00193 
00194 void par_cmdline(int argc, char *argv[])
00195 {
00196   int i;
00197   char *sp, *ep;
00198   char *block, *name, *value;
00199   Block *bp;
00200   Par *pp;
00201   int len;
00202 
00203   if (debug) printf("PAR_CMDLINE: \n");
00204   for (i=1; i<argc; i++) {
00205     block = argv[i];
00206     sp = strchr(block,'/');
00207     if ((sp = strchr(block,'/')) == NULL) continue;
00208     *sp = '\0';
00209     name = sp + 1;
00210 
00211     if((ep = strchr(name,'=')) == NULL){
00212       *sp = '/'; /* Repair argv[i] */
00213       continue;
00214     }
00215     *ep = '\0';
00216     value = ep + 1;
00217 
00218     if (debug) printf("PAR_CMDLINE: %s/%s=%s\n",block,name,value);
00219     bp = find_block(block);
00220     if (bp == NULL) ath_error("par_cmdline: Block \"%s\" not found\n",block);
00221     pp = find_par(bp,name);
00222     if (pp == NULL) ath_error("par_cmdline: Par \"%s\" not found\n",name);
00223     free(pp->value);
00224     pp->value = my_strdup(value);
00225 
00226     len = (int)strlen(value); /* Update the maximum Par value length */
00227     bp->max_value_len = len > bp->max_value_len ? len : bp->max_value_len;
00228 
00229 /* Repair argv[i] */
00230     *sp = '/';
00231     *ep = '=';
00232   }
00233 }
00234 
00235 /*----------------------------------------------------------------------------*/
00236 /*! \fn int par_exist(char *block, char *name) 
00237  *  \brief Return 0 or 1 if a block/name exists */
00238 
00239 int par_exist(char *block, char *name)
00240 {
00241   Block *bp;
00242   Par *pp;
00243 
00244   if (!now_open) ath_error("par_exist: No open parameter file\n");
00245   if (block == NULL) ath_error("par_exist: no block name specified\n");
00246   if (name  == NULL) ath_error("par_exist: no par name specified\n");
00247   bp = find_block(block);
00248   if (bp == NULL) return 0;
00249   pp = find_par(bp,name);
00250   return (pp == NULL ? 0 : 1);
00251 }
00252 
00253 /*----------------------------------------------------------------------------*/
00254 /*! \fn  char  *par_gets(char *block, char *name)
00255  *  \brief Return a string */
00256 
00257 char  *par_gets(char *block, char *name)
00258 {
00259   char *pp = par_getsl(block,name);
00260   return my_strdup(pp);
00261 }
00262 
00263 /*----------------------------------------------------------------------------*/
00264 /*! \fn  int    par_geti(char *block, char *name)
00265  *  \brief Return an integer */
00266 
00267 int    par_geti(char *block, char *name)
00268 {
00269   char *pp = par_getsl(block,name);
00270   return atoi(pp);
00271 }
00272 
00273 /*----------------------------------------------------------------------------*/
00274 /*! \fn double par_getd(char *block, char *name)
00275  *  \brief Return a Real value */
00276 
00277 double par_getd(char *block, char *name)
00278 {
00279   char *pp = par_getsl(block,name);
00280   return atof(pp);
00281 }
00282 
00283 /*----------------------------------------------------------------------------*/
00284 /*! \fn  char  *par_gets_def(char *block, char *name, char *def)
00285  *  \brief Return string *name in *block if it exists, else use
00286  *   the string *def as a default value */
00287 
00288 char  *par_gets_def(char *block, char *name, char *def)
00289 {
00290   if (par_exist(block,name)) {
00291     char *pp = par_getsl(block,name);
00292     return my_strdup(pp);
00293   }
00294 
00295   par_sets(block,name,def,"Default Value");
00296   return my_strdup(def);
00297 }
00298 
00299 /*----------------------------------------------------------------------------*/
00300 /*! \fn int  par_geti_def(char *block, char *name, int def)
00301  *  \brief Return integer *name in *block if it exists, else use
00302  *   the integer def as a default value */
00303 
00304 int  par_geti_def(char *block, char *name, int def)
00305 {
00306   if (par_exist(block,name)) {
00307     char *pp = par_getsl(block,name);
00308     return atoi(pp);
00309   }
00310 
00311   par_seti(block,name,"%d",def,"Default Value");
00312   return def;
00313 }
00314 
00315 /*----------------------------------------------------------------------------*/
00316 /*! \fn double par_getd_def(char *block, char *name, double def) 
00317  *  \brief Return double *name in *block if it exists, else use
00318  *   the double def as a default value  */
00319 
00320 double par_getd_def(char *block, char *name, double def)
00321 {
00322   if (par_exist(block,name)) {
00323     char *pp = par_getsl(block,name);
00324     return atof(pp);
00325   }
00326 
00327   par_setd(block,name,"%.15e",def,"Default Value");
00328   return def;
00329 }
00330 
00331 /*----------------------------------------------------------------------------*/
00332 /*! \fn void par_sets(char *block, char *name, char *sval, char *comment)
00333  *  \brief Set or add a string */
00334 
00335 void par_sets(char *block, char *name, char *sval, char *comment)
00336 {
00337   Block *bp = add_block(block);  /* find or add a block with this name */
00338 
00339   add_par(bp,name,sval,comment); /* Add the name = value pair Parameter */
00340   return;
00341 }
00342 
00343 /*----------------------------------------------------------------------------*/
00344 /*! \fn void par_seti(char *block, char *name, char *fmt, int ival, 
00345  *                    char *comment)
00346  *  \brief Set or add an integer */
00347 
00348 void par_seti(char *block, char *name, char *fmt, int ival, char *comment)
00349 {
00350   Block *bp = add_block(block);  /* find or add a block with this name */
00351   char sval[MAXLEN];
00352 
00353   sprintf(sval,fmt,ival);
00354   add_par(bp,name,sval,comment); /* Add the name = value pair Parameter */
00355   return;
00356 }
00357 
00358 /*----------------------------------------------------------------------------*/
00359 /*! \fn void par_setd(char *block, char *name, char *fmt, double dval,
00360  *                    char *comment)
00361  *  \brief Set or add a double */
00362 
00363 void par_setd(char *block, char *name, char *fmt, double dval, char *comment)
00364 {
00365   Block *bp = add_block(block);  /* find or add a block with this name */
00366   char sval[MAXLEN];
00367 
00368   sprintf(sval,fmt,dval);
00369   add_par(bp,name,sval,comment); /* Add the name = value pair Parameter */
00370   return;
00371 }
00372 
00373 /*----------------------------------------------------------------------------*/
00374 /*! \fn void par_dump(int mode, FILE *fp)
00375  *  \brief  Debugging aid: print out the current status of all Blocks/Pars */
00376 
00377 void par_dump(int mode, FILE *fp)
00378 {
00379   char fmt[80];
00380   Block *bp;
00381   Par *pp;
00382 
00383   if(mode != 2)
00384     fprintf(fp,"# --------------------- PAR_DUMP -----------------------\n\n");
00385 
00386   for(bp = base_block; bp != NULL; bp = bp->next){
00387     if (mode == 1) 
00388       fprintf(fp,"%s::\n",bp->name);
00389     else{
00390       fprintf(fp,"<%s>\n",bp->name);
00391       sprintf(fmt,"%%-%ds = %%-%ds",bp->max_name_len,bp->max_value_len);
00392     }
00393 
00394     for(pp = bp->p; pp != NULL; pp = pp->next){
00395       if (mode == 1)
00396         fprintf(fp," %s/%s = %s\n",bp->name,pp->name,pp->value);
00397       else{
00398         fprintf(fp,fmt,pp->name,pp->value);
00399         if(pp->comment == NULL) fprintf(fp,"\n");
00400         else fprintf(fp," # %s\n",pp->comment);
00401       }
00402     }
00403     fputc('\n',fp);
00404   }
00405 
00406   if(mode == 2)
00407     fprintf(fp,"<par_end>\n");
00408   else
00409     fprintf(fp,"# --------------------- PAR_DUMP -------------------------\n");
00410 
00411   return;
00412 }
00413 
00414 /*----------------------------------------------------------------------------*/
00415 /*! \fn void par_close(void)
00416  *  \brief Close up shop, free memory  */
00417 
00418 void par_close(void)
00419 {
00420   if (!now_open){
00421     fprintf(stderr,"[par_close]: No open parameter file\n");
00422     return;
00423   }
00424   now_open = 0;
00425   free_all();
00426 }
00427 
00428 /*----------------------------------------------------------------------------*/
00429 /*! \fn void par_dist_mpi(const int mytid, MPI_Comm comm)
00430  *  \brief Distribute the doubly linked list of parsed information to
00431  *   the children.
00432  */
00433 
00434 #ifdef MPI_PARALLEL
00435 void par_dist_mpi(const int mytid, MPI_Comm comm)
00436 {
00437   char line[MAXLEN];
00438   Block *bp = NULL;
00439   Par *pp;
00440   int count;
00441   char *block_name;
00442 
00443   if(mytid == 0){    /* I'm the rank=0 process */
00444     if (!now_open) ath_error("Parameter file is not open\n");
00445     if(debug)
00446       fprintf(stdout,"[par_dist_mpi]: Sending Parameter file \"%s\"\n",
00447               now_filename);
00448 
00449 /* Share the filename with the children */
00450     count = 1 + (int)strlen(now_filename);
00451     if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00452       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00453 /* printf("[tid=%d]: filename length = %d\n",mytid,count); */
00454     if(MPI_SUCCESS != MPI_Bcast(now_filename, count, MPI_CHAR, 0, comm))
00455       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00456 
00457     for(bp = base_block; bp != NULL; bp = bp->next){
00458 /* Rebuild the "<block>" string */
00459       sprintf(line,"<%s>",bp->name);
00460 
00461 /* Broadcast the block string */
00462       count = 1 + (int)strlen(line);
00463       if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00464         ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00465       if(MPI_SUCCESS != MPI_Bcast(line, count, MPI_CHAR, 0, comm))
00466         ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00467 
00468       for(pp = bp->p; pp != NULL; pp = pp->next){
00469 /* Rebuild the "name = value # comment" string */
00470         if(pp->comment == NULL)
00471           sprintf(line,"%s = %s",pp->name,pp->value);
00472         else
00473           sprintf(line,"%s = %s # %s",pp->name,pp->value,pp->comment);
00474 
00475 /* Broadcast the "name = value # comment" string */
00476         count = 1 + (int)strlen(line);
00477         if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00478           ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00479         if(MPI_SUCCESS != MPI_Bcast(line, count, MPI_CHAR, 0, comm))
00480           ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00481       }
00482     }
00483 
00484     count = -1;   /* Signal that we are done */
00485     if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00486       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00487     if(debug)
00488       fprintf(stdout,"[par_dist_mpi]: Parent all done...\n");
00489   }
00490   else{    /* I'm a Child */
00491     if (now_open) ath_error("Parameter %s file is already open\n",now_filename);
00492 
00493 /* Get the filename from the parent */
00494     if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00495       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00496 /* printf("[tid=%d]: filename length = %d\n",mytid,count); */
00497     if(MPI_SUCCESS != MPI_Bcast(line, count, MPI_CHAR, 0, comm))
00498       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00499     now_filename = my_strdup(line);
00500 /* printf("[tid=%d]: filename length = \"%s\"\n",mytid,now_filename); */
00501     now_open = 1;
00502     if(debug)
00503       fprintf(stdout,"[par_dist_mpi]: Recieving Parameter file \"%s\"\n",
00504               now_filename);
00505 
00506     if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00507       ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00508     while(count > 0){
00509       if(MPI_SUCCESS != MPI_Bcast(line, count, MPI_CHAR, 0, comm))
00510         ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00511 
00512       if (*line == '<') {                   /* a new Block */
00513         block_name = line_block_name(line); /* extract name from <name> */
00514         bp = add_block(block_name); /* find or add a block with this name */
00515       }
00516       else
00517         add_par_line(bp,line);              /* add par to this block */
00518 
00519       if(MPI_SUCCESS != MPI_Bcast(&count, 1, MPI_INT, 0, comm))
00520         ath_error("[par_dist_mpi]: Error on calling MPI_Bcast\n");
00521     }
00522 
00523     if(debug)
00524       fprintf(stdout,"[par_dist_mpi]: Child all done...\n");
00525   }
00526 
00527   return;
00528 }
00529 #endif /* MPI_PARALLEL */
00530 
00531 /*=========================== PRIVATE FUNCTIONS ==============================*/
00532 
00533 /*--------------------------------------------------------------------------- */
00534 /*! \fn static void *allocate(size_t size) 
00535  *  \brief Handy to call if you want to be certain to get the memory, 
00536  *   else it will die here
00537  */
00538 
00539 static void *allocate(size_t size) 
00540 {
00541   void *mem = calloc(1,size);
00542 
00543   if(mem == NULL) ath_error("allocate: not enough memory for %d bytes\n",size);
00544   return mem;
00545 }
00546 
00547 /*----------------------------------------------------------------------------*/
00548 /*! \fn static char *my_strdup(char *in)
00549  *  \brief A simple wrapper for strdup which dies in case of failure.  */
00550 
00551 static char *my_strdup(char *in)
00552 {
00553   char *out = ath_strdup(in);
00554   if(out == NULL) ath_error("Error allocating memory for a new string\n");
00555   return out;
00556 }
00557 
00558 /*----------------------------------------------------------------------------*/
00559 /*! \fn static char *skipwhite(char *cp)
00560  *  \brief Skip whitespace, returning pointer to next location of
00561  *    non-whitespace, or NULL
00562  */
00563 
00564 static char *skipwhite(char *cp)
00565 {
00566   while(isspace(*cp))
00567     cp++;
00568   return cp;
00569 }
00570 
00571 /*----------------------------------------------------------------------------*/
00572 /*! \fn static void str_term(char *cp)
00573  *  \brief Terminate a string, removing any extra white space at the end
00574  *   of the string. Input char pointer points to the terminating character,
00575  *   e.g. '\0'.
00576  */
00577 
00578 static void str_term(char *cp)
00579 {
00580   do{                           /* Remove any trailing white space */
00581     cp--;
00582   }while(isspace(*cp));
00583 
00584   *(++cp) = '\0';               /* Terminate the string */
00585 
00586   return;
00587 }
00588 
00589 /*----------------------------------------------------------------------------*/
00590 /*! \fn static char *line_block_name(char *line) 
00591  *  \brief Extract a block name from a line containing <block>
00592  *   Note it returns pointer into a patched piece of the input 'line'
00593  */
00594 
00595 static char *line_block_name(char *line) 
00596 {
00597   char *sp, *cp;
00598 
00599 /* We assume that (*line == '<') is true */
00600 /* Skip leading white space and remember the start of block name */
00601   sp = cp = skipwhite(line+1);
00602   while (*cp != '\0' && *cp != '>')
00603     cp++;
00604   if (*cp != '>') ath_error("Blockname %s does not appear terminated\n",sp);
00605   str_term(cp);      /* patch the line and remove any trailing white space */
00606 
00607   return sp;         /* return pointer into the now patched input string */
00608 }
00609 
00610 /*----------------------------------------------------------------------------*/
00611 /*! \fn static void add_par(Block *bp, char *name, char *value, char *comment)
00612  *  \brief Add a name = value # comment set to the Par list in the
00613  *   block *bp.  
00614  *
00615  *  If a parameter with the input name exists the value is
00616  *   replaced and if the input comment string is non-NULL it is also overwritten
00617  */
00618 
00619 static void add_par(Block *bp, char *name, char *value, char *comment)
00620 {
00621   Par *pp;
00622   Par **pnext;
00623   int len;
00624 
00625   len = (int)strlen(name); /* Update the maximum Par name length */
00626   bp->max_name_len  = len > bp->max_name_len  ? len : bp->max_name_len;
00627 
00628   len = (int)strlen(value); /* Update the maximum Par value length */
00629   bp->max_value_len = len > bp->max_value_len ? len : bp->max_value_len;
00630 
00631   if(debug){
00632     printf("   add_par: %-16s = %s",name,value);
00633     if(comment == NULL) printf("\n");
00634     else printf(" # %s\n",comment);
00635     printf("   max_name_len  = %d\n   max_value_len = %d\n",
00636            bp->max_name_len,bp->max_value_len);
00637   }
00638 
00639   for(pnext = &(bp->p); (pp = *pnext) != NULL; pnext = &(pp->next)){
00640     if(strcmp(pp->name,name) == 0){          /* if name already given earlier */
00641 /* Replace the value with the new value */
00642       free(pp->value);
00643       pp->value = my_strdup(value);
00644 /* Optionally replace the comment with the new comment */
00645       if(comment != NULL){
00646         if(pp->comment != NULL) free(pp->comment);
00647         pp->comment = my_strdup(comment);
00648       }
00649       return;
00650     }
00651   }
00652 
00653 /* Allocate a new Par and set pp to point to it */
00654   pp = *pnext = (Par *) allocate(sizeof(Par));
00655 
00656   pp->name = my_strdup(name);   /* save name */
00657   pp->value = my_strdup(value); /* save value */
00658   pp->comment = (comment == NULL ? NULL : my_strdup(comment)); /* comment? */
00659   pp->next = NULL;              /* Terminate the chain */
00660   return;
00661 }
00662 
00663 /*----------------------------------------------------------------------------*/
00664 /*! \fn static void add_par_line(Block *bp, char *line)
00665  *  \brief Parse a line, assume it's "key = value # comment" 
00666  *   and add it into a block
00667  */
00668 
00669 static void add_par_line(Block *bp, char *line)
00670 {
00671   char *cp;
00672   char *name, *equal=NULL, *value=NULL, *hash=NULL, *comment=NULL, *nul;
00673 
00674   if(bp == NULL)
00675     ath_error("[add_par_line]: (no block name) while parsing line \n%s\n",line);
00676 
00677   name = skipwhite(line);           /* name */
00678 
00679   for(cp = name; *cp != '\0'; cp++){/* Find the first '=' and '#' */
00680     if(*cp == '='){
00681       if(equal == NULL){
00682         equal = cp;                 /* store the equals sign location */
00683         value = skipwhite(cp + 1);  /* value */
00684       }
00685     }
00686     if(*cp == '#'){
00687       hash = cp;                    /* store the hash sign location */
00688       comment = skipwhite(cp + 1);  /* comment */
00689       break;
00690     }
00691   }
00692 
00693   while(*cp != '\0') cp++;          /* Find the NUL terminator */
00694   nul = cp;
00695 
00696   if(equal == NULL)
00697     ath_error("No '=' found in line \"%s\"\n",line);
00698 
00699   str_term(equal);                  /* Terminate the name string */
00700 
00701   if(hash == NULL){
00702     str_term(nul);                  /* Terminate the value string */
00703   }
00704   else{
00705     str_term(hash);                 /* Terminate the value string */
00706 
00707     if(*comment == '\0')
00708       comment = NULL;               /* Comment field is empty */
00709     else
00710       str_term(nul);                /* Terminate the comment string */
00711   }
00712 
00713   add_par(bp,name,value,comment);
00714 }
00715 
00716 /*----------------------------------------------------------------------------*/
00717 /*! \fn static Block *add_block(char *name)
00718  *  \brief Find or add a new named Block */
00719 
00720 static Block *add_block(char *name)
00721 {
00722   Block *bp;
00723   Block **pnext;
00724 
00725   if (debug) printf("add_block: %s\n",name);
00726 
00727   for(pnext = &base_block; (bp = *pnext) != NULL; pnext = &(bp->next)){
00728     if(strcmp(bp->name,name) == 0) return bp;
00729   }
00730 /* Allocate a new Block and set bp to point to it */
00731   bp = *pnext = (Block *) allocate(sizeof(Block));
00732 
00733   bp->name = my_strdup(name); /* Store the Block name */
00734   bp->p = NULL;               /* Terminate the Par list */
00735   bp->max_name_len  = 0;      /* no Pars - no names */
00736   bp->max_value_len = 0;      /* no Pars - no values */
00737   bp->next = NULL;            /* Terminate the Block list */
00738   return bp;
00739 }
00740 
00741 /*----------------------------------------------------------------------------*/
00742 /*! \fn static Block *find_block(char *name)
00743  *  \brief Check if a Block name already exists */
00744 
00745 static Block *find_block(char *name)
00746 {
00747   Block *bp;
00748 
00749   if (debug) printf("find_block: %s\n",name);
00750   for(bp = base_block; bp != NULL; bp = bp->next){
00751     if (strcmp(bp->name,name) == 0) return bp;
00752   }
00753 
00754   return NULL;
00755 }
00756 
00757 /*----------------------------------------------------------------------------*/
00758 /*! \fn static Par *find_par(Block *bp, char *name)
00759  *  \brief Check if a Block contains a Par with certain name */
00760 
00761 static Par *find_par(Block *bp, char *name)
00762 {
00763   Par *pp;
00764 
00765   if (debug) printf("find_par: %s\n",name);
00766   for(pp = bp->p; pp != NULL; pp = pp->next){
00767     if (strcmp(pp->name,name) == 0) return pp;
00768   }
00769 
00770   return NULL;
00771 }
00772 
00773 /*----------------------------------------------------------------------------*/
00774 /*! \fn static void free_all(void)
00775  *  \brief Free all stuff associated with Block's and Par's */
00776 
00777 static void free_all(void)
00778 {
00779   Block *bp1, *bp;
00780   Par *pp1, *pp;
00781 
00782   if (now_filename) free(now_filename);
00783   now_filename = NULL; /* Return to the initial, empty state */
00784 
00785   for(bp = base_block; bp != NULL; bp = bp1){ /* loop over all blocks */
00786     bp1 = bp->next; /* store the pointer to the next block */
00787     for(pp = bp->p; pp != NULL; pp = pp1){ /* loop over all pars */
00788       pp1 = pp->next; /* store the pointer to the next par */
00789       if (pp->name)    free(pp->name);
00790       if (pp->value)   free(pp->value);
00791       if (pp->comment) free(pp->comment);
00792       free(pp);
00793     }
00794     if (bp->name) free(bp->name);
00795     free(bp);
00796   }
00797   base_block = NULL; /* Return to the initial, empty state */
00798 }
00799 
00800 /*----------------------------------------------------------------------------*/
00801 /*! \fn static char *par_getsl(char *block, char *name)
00802  *  \brief Helper function to return a local string. external clients should
00803  *   call par_gets, which returns a newline allocate string
00804  */
00805 
00806 static char *par_getsl(char *block, char *name)
00807 {
00808   Block *bp;
00809   Par *pp;
00810 
00811   if (!now_open) ath_error("par_gets: No open parameter file\n");
00812   if (block == NULL) ath_error("par_gets: no block name specified\n");
00813   if (name  == NULL) ath_error("par_gets: no par name specified\n");
00814   bp = find_block(block);
00815   if (bp == NULL) ath_error("par_gets: Block \"%s\" not found\n",block);
00816   pp = find_par(bp,name);
00817   if (pp == NULL)
00818     ath_error("par_gets: Par \"%s\" not found in Block \"%s\"\n",name,block);
00819   return pp->value;
00820 }
00821 
00822 /*----------------------------------------------------------------------------*/
00823 /*! \fn void par_debug(int level)
00824  *  \brief Set debug flag to level.  Call with argument=1 to enable 
00825  *   diagnositc output.    Alas, not really for the outside world to use */
00826 
00827 void par_debug(int level) {      /* un - advertised :-) */
00828   debug = level;
00829 }
00830 
00831 /*----------------------------------------------------------------------------*/
00832 /* see Makefile for the target 'par:' to test these functions */
00833 /* Essentially:  cc -DTESTBED -g -o par par.c                 */
00834 
00835 #if defined(TESTBED)
00836 #if defined MPI_PARALLEL
00837 int main(int argc, char *argv[])
00838 {
00839   int mytid;
00840 /* int numprocs; */
00841   int  namelen;
00842   char processor_name[MPI_MAX_PROCESSOR_NAME];
00843 
00844   par_debug(0);
00845 
00846   if(MPI_SUCCESS != MPI_Init(&argc,&argv))
00847     ath_error("Error on calling MPI_Init\n");
00848 /* Get the number of processes */
00849 /* MPI_Comm_size(MPI_COMM_WORLD,&numprocs); */
00850 /* Get my task id, or rank as it is called in MPI */
00851   MPI_Comm_rank(MPI_COMM_WORLD,&mytid);
00852 /* Get the name of the processor or machine name */
00853   MPI_Get_processor_name(processor_name,&namelen);
00854 
00855   printf("My task id / rank = %d on %s\n",mytid, processor_name);
00856 
00857 /* Parent and child have different jobs */
00858   if(mytid != 0)
00859     printf("My Parent's task id / rank = 0\n");
00860   else{
00861     printf("I am the Parent\n");
00862 
00863     if (argc == 1) {
00864       printf("Usage: %s par-file [block-name par-name]\n",argv[0]);
00865       exit(0);
00866     }
00867 
00868     par_open(argv[1]);
00869     par_cmdline(argc,argv);
00870     if (argc == 4) {
00871       char *cp = par_gets(argv[2],argv[3]);
00872       printf("PAR_GETS: %s.%s = \"%s\"\n",argv[2],argv[3],cp);
00873       printf("PAR_GETI: %s.%s = \"%d\" as integer\n",
00874         argv[2],argv[3],par_geti(argv[2],argv[3]));
00875       printf("PAR_GETD: %s.%s = \"%g\" as double\n",
00876         argv[2],argv[3],par_getd(argv[2],argv[3]));
00877       free(cp);
00878     }
00879   }
00880  
00881   par_dist_mpi(mytid,MPI_COMM_WORLD);
00882   par_dump(0,stdout);
00883   par_close();
00884 
00885   MPI_Finalize();
00886 
00887   return 0;
00888 }
00889 
00890 #else /* SERIAL */
00891 
00892 int main(int argc, char *argv[])
00893 {
00894   if (argc == 1) {
00895     printf("Usage: %s par-file [block-name par-name]\n",argv[0]);
00896     exit(0);
00897   }
00898 
00899   par_debug(0);
00900   par_open(argv[1]);
00901   par_cmdline(argc,argv);
00902   if (argc == 4) {
00903     char *cp = par_gets(argv[2],argv[3]);
00904     int ival;
00905     double dval;
00906     char *sval = "hello world";
00907     printf("PAR_GETS: %s.%s = \"%s\"\n",argv[2],argv[3],cp);
00908     printf("PAR_GETI: %s.%s = \"%d\" as integer\n",
00909       argv[2],argv[3],par_geti(argv[2],argv[3]));
00910     printf("PAR_GETD: %s.%s = \"%g\" as double\n",
00911       argv[2],argv[3],par_getd(argv[2],argv[3]));
00912     free(cp);
00913   }
00914   par_dump(0,stdout);
00915   par_close();
00916   return 0;
00917 }
00918 #endif /* MPI_PARALLEL or SERIAL */
00919 #endif

Generated on Mon Sep 27 2010 23:03:07 for Athena by  doxygen 1.7.1