arguments.cpp

00001 /*
00002  * All of the documentation and software included in the
00003  * Alchemy Software is copyrighted by Stanley Kok, Parag
00004  * Singla, Matthew Richardson, Pedro Domingos, Marc
00005  * Sumner and Hoifung Poon.
00006  * 
00007  * Copyright [2004-07] Stanley Kok, Parag Singla, Matthew
00008  * Richardson, Pedro Domingos, Marc Sumner and Hoifung
00009  * Poon. All rights reserved.
00010  * 
00011  * Contact: Pedro Domingos, University of Washington
00012  * (pedrod@cs.washington.edu).
00013  * 
00014  * Redistribution and use in source and binary forms, with
00015  * or without modification, are permitted provided that
00016  * the following conditions are met:
00017  * 
00018  * 1. Redistributions of source code must retain the above
00019  * copyright notice, this list of conditions and the
00020  * following disclaimer.
00021  * 
00022  * 2. Redistributions in binary form must reproduce the
00023  * above copyright notice, this list of conditions and the
00024  * following disclaimer in the documentation and/or other
00025  * materials provided with the distribution.
00026  * 
00027  * 3. All advertising materials mentioning features or use
00028  * of this software must display the following
00029  * acknowledgment: "This product includes software
00030  * developed by Stanley Kok, Parag Singla, Matthew
00031  * Richardson, Pedro Domingos, Marc Sumner and Hoifung
00032  * Poon in the Department of Computer Science and
00033  * Engineering at the University of Washington".
00034  * 
00035  * 4. Your publications acknowledge the use or
00036  * contribution made by the Software to your research
00037  * using the following citation(s): 
00038  * Stanley Kok, Parag Singla, Matthew Richardson and
00039  * Pedro Domingos (2005). "The Alchemy System for
00040  * Statistical Relational AI", Technical Report,
00041  * Department of Computer Science and Engineering,
00042  * University of Washington, Seattle, WA.
00043  * http://www.cs.washington.edu/ai/alchemy.
00044  * 
00045  * 5. Neither the name of the University of Washington nor
00046  * the names of its contributors may be used to endorse or
00047  * promote products derived from this software without
00048  * specific prior written permission.
00049  * 
00050  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF WASHINGTON
00051  * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00052  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00053  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00054  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
00055  * OF WASHINGTON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00056  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00057  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00058  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00059  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00060  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00061  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00062  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00063  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00064  * 
00065  */
00066 //
00067 // *************************************************************************
00068 // * A general mechanism to parse command line and file arguments for C++.
00069 // * Jeff Bilmes
00070 // * <bilmes@media.mit.edu> Aug 1992
00071 // * See main() in arguments.cc for example.
00072 // * Compile with -DMAIN to demonstrate example.
00073 // *************************************************************************
00074 // 
00075 
00076 // TO DO and Known Bugs: 
00077 //   o A printDefault message should wait to print until
00078 //    all args are set (including those in files).
00079 //    Add another argument to parseFromCommandLine so it can tell what
00080 //    is the file to get input from. Do we want multiple such files?
00081 //   o Add ability to get parameters from stdin.
00082 //   o Fix bug with flagless and boolean arguments where
00083 //     we can do: program -boolarg flaglessargument
00084 //   o add the ability to have multiple arguments for one flag.
00085 //     i.e -flag <arg1> <arg2> ... <argn>
00086 //       ARGS("foo",ARGS::Req,a,b,c,d,e,"Takes (requires) 5 arguments");
00087 //     (or even an unknown number of arguments of one type,
00088 //         i.e. an array of ints, or of char*s).
00089 //       char **ptrp;
00090 //       int size_ptrp;
00091 //       ARGS("foo",ARGS::Req || ARGS:Unlimited,ptrp,size_ptrp,"Takes many char*s");
00092 //     isnumArg(char*) and isoptionArg(char*) routines will be useful.
00093 //   o Add ability to unsatisfy arguments (i.e. if a -q flag implies 
00094 //     needing a -p flag).
00095 //   o Add actions that get called after all arguments are set from
00096 //     command line, file, etc. so that user can check for special 
00097 //     requirements.
00098 //   o add types short,long,unsigned short, unsigned long, etc.
00099 //   o add ability for usage message to also print out default values.
00100 //   o Order of parsing arguments should be correct. I.e. in order
00101 //     of appearance on command line, and if command line is a file
00102 //     argument, that file should be parsed before subsequent command line
00103 //     arguments.
00104 //   o add bit arguments, where boolean flags can set or reset just one
00105 //     specified bit of an integer argument.
00106 //   o add ability to do "one of" arguments, e.g. a direction
00107 //        argument, "progr -dir up" where dir is checked to
00108 //        be up,down,left, or right and an error results if it isn't.
00109 //     possible oneof syntax:
00110 //         ARGS(
00111 //              ARGS("arg1",...),
00112 //              ARGS("arg2",...),
00113 //               ..
00114 //                 );
00115 //   o Arguments file should be piped through cpp. Comments should start with ";"
00116 //   o Make the entire package non-static so multiple args structs
00117 //     can be created.
00118 //   o Allow for different sets of valid arguments to be selected
00119 //     based on previous command line parameters.
00120 
00121 #include <sstream>
00122 //#include <iostream>
00123 #include <fstream>
00124 #include <stddef.h>
00125 #include <stdlib.h>
00126 
00127 /* files included by std.h
00128 #include <_G_config.h>
00129 #include <stddef.h>
00130 #include <stdlib.h>
00131 #include <string.h>
00132 #include <memory.h>
00133 #include <unistd.h>
00134 #include <stdio.h>
00135 #include <errno.h>
00136 #include <fcntl.h>
00137 */
00138 
00139 #include <string.h>
00140 #include <ctype.h>
00141 
00142 
00143 #include "arguments.h"
00144 
00145 ostream* ARGS::pout = NULL; //used to print parameters
00146 
00147 bool ARGS::__args__dummy__;
00148 ARGS ARGS::END(NULL,ARGS::Opt,ARGS::__args__dummy__, "");
00149 
00150 char* const ARGS::NOFLAG       = "noflg";
00151 char* const ARGS::NOFL_FOUND   = "nofl_fnd";
00152 bool        ARGS::usage_called = false;
00153 const char  ARGS::CommentChar  = '#';
00154 int         ARGS::numArgs      = 0;
00155 bool*       ARGS::found        = NULL;
00156 char*       ARGS::progName     = "";
00157 argsAction  ARGS::no_action;
00158 bool        ARGS::ignoreUnknownSwitch = false;
00159 
00160 
00161 void ARGS::init(char* m, argKind r, char* d, argsAction& a) 
00162 {
00163   flag = m;
00164   arg_kind = r;
00165   if (arg_kind == Tog) 
00166   {   // type must be boolean. Toggle is never a required arg.
00167     if (uc.type != unionClass::bool_t) 
00168     {
00169       Error("Internal: ARGS::ARGS() toggle argument must be bool");
00170       ::exit(1);
00171     }
00172   }
00173   description = d;
00174   if (&a == &no_action)
00175     action = NULL;
00176   else
00177     action = &a;
00178 }
00179 
00180 
00181 ARGS::ARGS() : uc(__args__dummy__) 
00182 {
00183   init(NULL,ARGS::Opt,"",no_action);
00184 }
00185 
00186 
00187 ARGS::ARGS(char* m , argKind r, unionClass ucl, char* d, argsAction& a): uc(ucl) 
00188 {
00189   init(m,r,d,a);
00190 }
00191 
00192 
00193 ARGS::ARGS(argKind r, unionClass ucl, char* d, argsAction& a) : uc(ucl) 
00194 {
00195   init(NOFLAG,r,d,a);
00196 }
00197 
00198 
00199 ARGS::ARGS(unionClass ucl,char* d,argsAction& a) : uc(ucl) 
00200 {
00201   init(NOFLAG,Opt,d,a);
00202 }
00203 
00204 
00205 ARGS::ARGS(const ARGS& a) : uc(a.uc) 
00206 {
00207   flag = a.flag;
00208   arg_kind = a.arg_kind;
00209   description = a.description;
00210   action = a.action;
00211 }
00212 
00213 
00214 void ARGS::makeFound() 
00215 {
00216   if (found != NULL)
00217     return;
00218   numArgs = 0;
00219   ARGS* args_iter = Args;
00220   while (args_iter->flag != NULL) 
00221   {
00222     numArgs ++;
00223     args_iter++;
00224   }
00225   found = new bool[numArgs];
00226   for (int i = 0; i < numArgs; i++) 
00227     found[i] = false;
00228 }
00229 
00230   //TO DO: this is still not perfect.
00231   //One problem occurs when arg is an optional char*, error msg is
00232   //"free(): invalid pointer 0x80c3f80!"
00233 void ARGS::cleanUp()
00234 {
00235   delete [] found;
00236   for (int i = 0; i < numArgs; i++)
00237   {
00238     if (Args[i].uc.type == unionClass::str_t)
00239       delete [] Args[i].uc.ptr->string;
00240   }
00241 }
00242 
00243 
00244 ARGS::ArgsRetCode 
00245 ARGS::parseFromCommandLine(int argc, char** argv)
00246 {
00247   ARGS::ArgsRetCode retCode = ARG_OK; 
00248 
00249   if (argv[0] != NULL)
00250     progName = argv[0];
00251   makeFound();
00252   ARGS* args_iter;
00253   for (int i = 1; i < argc;i++) 
00254   {
00255     if (argv[i][0] == '-') 
00256     {
00257       char* flag = argv[i];
00258       args_iter = findMatch(Args, &flag[1]);
00259       if (args_iter == NULL) 
00260       {
00261         if (ignoreUnknownSwitch == false) 
00262         {
00263           Error("Unknown switch: ",argv[i]);
00264           return (ARG_ERR);
00265         }
00266       } 
00267       else 
00268       if (args_iter == (ARGS*)(-1)) 
00269       {
00270         Error("Ambiguous switch: ",argv[i]);
00271         return (ARG_ERR);
00272       } 
00273       else 
00274       {
00275         char* arg;
00276         if ((i+1) >= argc)  arg = NULL;
00277         else                arg = argv[++i];
00278         ARGS::ArgsRetCode ok;
00279         ok = argsSwitch(args_iter,arg,i, found[args_iter - Args],flag);
00280         if (ok==ARG_ERR) retCode = ARG_ERR;
00281       }
00282     } 
00283     else 
00284     {   // Go through and look for no flag case, in order.
00285       args_iter = Args;
00286       while (args_iter->flag != NULL) 
00287       {
00288         if (args_iter->flag == NOFLAG) 
00289         {
00290           // assume string type
00291           char* arg = argv[i];
00292           int dummy;
00293           ARGS::ArgsRetCode ok;
00294           ok = argsSwitch(args_iter,arg,dummy,found[args_iter-Args],"");
00295           if (ok==ARG_ERR) retCode = ARG_ERR;
00296           args_iter->flag = NOFL_FOUND;
00297           break;
00298         }
00299         args_iter++;
00300       }
00301     }
00302   }
00303   if (checkMissing())
00304     return ARG_MISSING;
00305   return retCode;
00306 }
00307 
00308 
00309 bool ARGS::checkMissing(bool printMessage) 
00310 {
00311   ARGS* args_iter;
00312   args_iter = Args;
00313   bool missing = false;
00314   while (args_iter->flag != NULL) 
00315   {
00316     if (!found[args_iter-Args] && args_iter->arg_kind == Req) 
00317     {
00318       if (printMessage) 
00319       {
00320         ostringstream oss;
00321         if (noFlagP(args_iter->flag))  oss << "";
00322         else                           oss << " -" << args_iter->flag;
00323         oss << " " << args_iter->uc.type;
00324         Error("Required argument missing:",oss.str().c_str());
00325       }
00326       missing = true;
00327     }
00328     args_iter++;
00329   }
00330   return missing;
00331 }
00332 
00333 
00334   // LIBG++ 2.2 dependant.
00335   // THIS FUNCTION WILL NEED RE-WRITING AS libg++ 2.2 fixes bugs.
00336   // Still currently can't have lines with no characters in them. It messes
00337   // up libg++ 2.2's internal state.
00338 ARGS::ArgsRetCode ARGS::parseFromFile(char* fileName)
00339 {
00340   makeFound();
00341   ifstream ifile(fileName);
00342   if (!ifile) 
00343   {
00344     Error("Can't file argument file: ",fileName);
00345     return ARG_ERR;
00346   } 
00347   else 
00348   {
00349       // get the arguments from the file.
00350     char buffer[512];
00351     char buffer_orig[512];
00352     char c;
00353     while (ifile.good()) 
00354     { 
00355       ifile.get(buffer,512,'\n');
00356       // ****************************
00357       // ** LIBG++ VERSION 2.2 BUG WORK-AROUND 
00358       // ****************************
00359       //if (ifile.flags() | ios::failbit && ::strlen(buffer) == 0)
00360       //  ifile.unsetf(ios_base::failbit);         
00361       // ****************************
00362       // ** END OF LIBG++ BUG WORK-AROUND  
00363       // ****************************
00364       if (ifile.get(c) && c != '\n') 
00365       {
00366           // input string is longer than expected.
00367         Error("Line length too long in file: ",fileName);
00368         return ARG_ERR; // give up
00369       }
00370       ::strcpy(buffer_orig,buffer);
00371       char* buffp = buffer;
00372       while (*buffp) 
00373       {
00374         if (*buffp == CommentChar)
00375           *buffp = '\0';
00376         buffp++;
00377       }
00378 
00379       buffp = buffer;
00380         // skip space
00381       while (*buffp == ' ' || *buffp == '\t')
00382         buffp++;
00383         // get flag
00384       char* flag = buffp;
00385       char* arg;
00386         // get command up to space or ':'
00387       while (*buffp && *buffp != ' ' && *buffp != '\t' &&  *buffp != ':')
00388         buffp++;
00389       if (buffp == flag)
00390         continue; // empty line.
00391       
00392       if (*buffp) 
00393       { 
00394         // get ':' and position buffp to start of arg.
00395         if (*buffp == ':')
00396           *buffp++ = '\0'; // we have the flag
00397         else 
00398         {   // we have the flag, but need to get rid of ':' if there.
00399           *buffp++ = '\0'; 
00400           while (*buffp && *buffp != ':')
00401             buffp++;
00402           if (*buffp == ':')
00403             buffp++;
00404         }
00405         // skip space
00406         while (*buffp == ' ' || *buffp == '\t')
00407           buffp++;
00408       }
00409 
00410       if (!*buffp)
00411         arg = NULL;
00412       else 
00413       {
00414         arg = buffp;
00415           // get command up to space
00416         while (*buffp && *buffp != ' ' && *buffp != '\t')
00417           buffp++;      
00418         *buffp = '\0';
00419       }      
00420       ARGS* args_iter = findMatch(Args,flag);
00421       if (args_iter == NULL) 
00422       {
00423         Error("Unknown switch in ",fileName,": ",flag);
00424         return (ARG_ERR);
00425       } 
00426       else 
00427       if (args_iter == (ARGS*)(-1)) 
00428       {
00429         Error("Ambiguous switch in ",fileName,": ",flag);
00430         return (ARG_ERR);
00431       } 
00432       else 
00433       {
00434           // In a file, only set arg if it hasn't been set before. This
00435           // allows command line arguments to take precedence, but arguments
00436           // in files are only set once.
00437         if (found[args_iter-Args] != true) 
00438         {
00439           int i;
00440           if (argsSwitch(args_iter,arg,i,found[args_iter - Args],flag) 
00441               != ARG_OK) 
00442           {
00443             Error("Error in ",fileName);
00444             return (ARG_ERR);
00445           }
00446         }
00447       }
00448     }
00449   }
00450   if (checkMissing())
00451     return ARG_MISSING;
00452   return ARG_OK;
00453 }
00454 
00455 
00456   // Return NULL for unknown switch, return (ARGS*)(-1) for ambiguous switch,
00457   // otherwise returns the ARGS* that matches.
00458 ARGS* ARGS::findMatch(ARGS* ag,char *flag) 
00459 {
00460   int flaglen     = ::strlen(flag);
00461   ARGS* args_iter = ag;
00462   int numTaged    = 0;  
00463   int lastTaged   = -1;
00464 
00465     // find the one that best matches.
00466   while (args_iter->flag != NULL) 
00467   {
00468     if (!noFlagP(args_iter->flag)) 
00469     {
00470       if (strlen(args_iter->flag) == strlen(flag) &&
00471           !::strncmp(args_iter->flag,flag,flaglen)) 
00472       {
00473         numTaged++;        
00474         lastTaged = (args_iter - ag);
00475       }
00476     }
00477     args_iter++;
00478   }
00479   if (numTaged == 0)     return NULL;
00480   else if (numTaged > 1) return (ARGS*)(-1);
00481   else                   return &ag[lastTaged];
00482 }
00483 
00484   // only returns ARGS::ARG_OK or ARG_ERR
00485 ARGS::ArgsRetCode 
00486 ARGS::argsSwitch(ARGS* args_iter, char* arg, int& index, bool& found,char* flag)
00487 {
00488   switch(args_iter->uc.type) 
00489   {
00490     // ---------------------------------------------------------------------
00491     case unionClass::bool_t: 
00492     {
00493       bool b = true; 
00494       if (arg == NULL || // end of arguments.
00495           arg[0] == '-') // for optionless flag, just turn on.
00496       {   
00497         // for bool case, just turn it on.
00498         if (args_iter->arg_kind != Tog)
00499           args_iter->uc.ptr->boolean = true;
00500         else
00501           args_iter->uc.ptr->boolean = 
00502             ((args_iter->uc.ptr->boolean == true) ? false : true);
00503 
00504         if (arg != NULL)
00505           index--;
00506         found = true;
00507         if (args_iter->action != NULL)
00508           args_iter->action->act(args_iter->uc.ptr->boolean);
00509         break;        
00510       }
00511 
00512         // If kind  is Tog and we have a valid boolean 
00513         // argument, then treat argument as normal explicit boolean argument.
00514       if (!boolable(arg,b)) 
00515       {
00516         Error("Boolean argument needed: ",flag," ",arg);
00517         return ARG_ERR;
00518       }
00519       args_iter->uc.ptr->boolean = b;
00520       
00521       found = true;
00522       if (args_iter->action != NULL)
00523         args_iter->action->act(args_iter->uc.ptr->boolean);
00524     }
00525     break;
00526     // ---------------------------------------------------------------------
00527     case unionClass::char_t: 
00528     {
00529       if (arg == NULL || // end of arguments.
00530           ::strlen(arg) != 1) 
00531       {
00532         Error("Character argument needed: ",flag," ",arg);
00533         return ARG_ERR;
00534       }
00535 
00536       args_iter->uc.ptr->ch = arg[0];
00537 
00538       found = true;
00539       if (args_iter->action != NULL)
00540         args_iter->action->act(args_iter->uc.ptr->ch);
00541     }
00542     break;
00543     // ---------------------------------------------------------------------
00544     case unionClass::str_t: 
00545     {
00546       if (arg == NULL) // end of arguments.
00547       { 
00548         Error("String argument needed: ",flag);
00549         return ARG_ERR;
00550       }
00551       args_iter->uc.ptr->string =
00552         ::strcpy(new char[strlen(arg)+1],arg);
00553 
00554       found = true;
00555       if (args_iter->action != NULL)
00556         args_iter->action->act(args_iter->uc.ptr->string);
00557     }
00558     break;
00559     // ---------------------------------------------------------------------
00560     case unionClass::int_t: 
00561     {
00562       if (arg == NULL)  // end of arguments.
00563       {
00564         Error("Integer argument needed: ",flag);
00565         return ARG_ERR;
00566       }
00567       int n;
00568       istringstream ist(arg);
00569       if (!(ist >> n)) 
00570       {
00571         Error("Integer argument needed: ",flag," ",arg);
00572         return ARG_ERR;
00573       }
00574       args_iter->uc.ptr->integer = n;
00575 
00576       found = true;
00577       if (args_iter->action != NULL)
00578         args_iter->action->act(args_iter->uc.ptr->integer);
00579     }
00580     break;
00581     // ---------------------------------------------------------------------
00582     case unionClass::uint_t: 
00583     {
00584       if (arg == NULL)  // end of arguments.
00585       {
00586         Error("Unsigned integer argument needed: ",flag);
00587         return ARG_ERR;
00588       }
00589       unsigned int n;
00590       istringstream ist(arg);
00591       if (!(ist >> n)) 
00592       {
00593         Error("Unsigned integer argument needed: ",flag," ",arg);
00594         return ARG_ERR;
00595       }
00596       args_iter->uc.ptr->uinteger = n;
00597 
00598       found = true;
00599       if (args_iter->action != NULL)
00600         args_iter->action->act(args_iter->uc.ptr->uinteger);
00601     }
00602     break;
00603     // ---------------------------------------------------------------------
00604     case unionClass::float_t: 
00605     {
00606       if (arg == NULL)  // end of arguments.
00607       {
00608         Error("Real number argument needed: ",flag);
00609         return ARG_ERR;
00610       }
00611       float f;
00612       istringstream ist(arg);
00613       if (!(ist >> f)) 
00614       {
00615         Error("Floating point number argument needed: ",flag," ",arg);
00616         return ARG_ERR;
00617       }
00618       args_iter->uc.ptr->single_prec = f;
00619 
00620       found = true;
00621       if (args_iter->action != NULL)
00622         args_iter->action->act(args_iter->uc.ptr->single_prec);
00623     }
00624     break;
00625     // ---------------------------------------------------------------------
00626     case unionClass::double_t: 
00627     {
00628       if (arg == NULL)   // end of arguments.
00629       {
00630         Error("Real number argument needed: ",flag);
00631         return ARG_ERR;
00632       }
00633       double d;
00634       istringstream ist(arg);
00635       if (!(ist >> d)) 
00636       {
00637         Error("Integer argument needed: ",flag," ",arg); 
00638         return ARG_ERR;
00639       }
00640       args_iter->uc.ptr->double_prec = d;
00641 
00642       found = true;
00643       if (args_iter->action != NULL)
00644         args_iter->action->act(args_iter->uc.ptr->double_prec);
00645     }
00646     break;
00647     // ---------------------------------------------------------------------
00648     case unionClass::action_t:
00649       // the argsAction* is stored in ptr itself.
00650       ((argsAction*)args_iter->uc.ptr)->act();
00651       if (arg != NULL)
00652         index--;
00653       found = true;
00654       if (args_iter->action != NULL)
00655         args_iter->action->act();
00656       break;
00657       // ---------------------------------------------------------------------
00658     default:
00659       Error("Unknown internal argument: Internal error.");
00660       ::exit(1);
00661       break;
00662   }
00663   return ARG_OK;
00664 }
00665 
00666 
00667 bool ARGS::boolable(char* string, bool& value)
00668 {
00669   bool rc;
00670   int arglen = strlen(string);
00671   char* upcasearg = new char[arglen+1];
00672   ::strcpy(upcasearg,string);
00673   for (int i = 0;i < arglen; i++)
00674     upcasearg[i] = toupper(upcasearg[i]);
00675   if (!::strncmp("TRUE", upcasearg, arglen) ||
00676       !::strncmp("YES",  upcasearg, arglen) ||
00677       !::strncmp("ON",   upcasearg, arglen) ||
00678       (arglen == 1 && string[0] == '1')) 
00679   {
00680     value = true;
00681     rc    = true;
00682   } 
00683   else 
00684   if (!::strncmp("FALSE", upcasearg, arglen) || 
00685             !::strncmp("NO",    upcasearg, arglen) || 
00686             !::strncmp("OFF",   upcasearg, arglen) || 
00687       (arglen == 1 && string[0] == '0')) 
00688   {
00689     value = false;
00690     rc    = true;
00691   } 
00692   else 
00693   {
00694     rc = false;
00695   }
00696   delete [] upcasearg;
00697   return rc;
00698 }
00699 
00700 
00701   // return true if there is no flag.
00702 bool ARGS::noFlagP(char* flg) 
00703 {
00704     // cant test here equality with NOFLAG, so do the following instread.
00705   if (flg == NOFLAG || flg == NOFL_FOUND)
00706     return true;
00707   else
00708     return false;
00709 }
00710 
00711 
00712 void ARGS::Error(const char* s1, const char* s2, const char* s3, const char* s4,
00713                  const char* s5)
00714 {
00715   cout << "Argument error: " << s1;
00716   if (s2 != NULL) cout << s2;
00717   if (s3 != NULL) cout << s3;
00718   if (s4 != NULL) cout << s4;
00719   if (s5 != NULL) cout << s5;
00720   cout << "\n";
00721 }
00722 
00723 
00724 void ARGS::usage(bool force) 
00725 {
00726   if (usage_called && !force)
00727     return;
00728   usage_called = true;
00729 
00730   cout << "Usage: " << progName << " [[[-flag] [option]] ...]\n";
00731   cout << "Required: <>; Optional: []; Flagless arguments must be in order.\n";
00732 
00733   ARGS* args_iter = Args;
00734   int longest_variation = 0;
00735 
00736   while (args_iter->flag != NULL) 
00737   {
00738     int len = 0;
00739     if (!noFlagP(args_iter->flag)) 
00740     {
00741         // add one for the '-', as in "-flag"
00742       len += ::strlen(args_iter->flag)+1;
00743       if (args_iter->uc.type != unionClass::action_t)
00744         len ++; //  add one for the ' ' in "-flag "
00745     }
00746     len += ::strlen(unionClass::typeStr(args_iter->uc.type));
00747     if (args_iter->uc.type != unionClass::action_t)
00748       len += 2; // add two for brackets. '[',']', or '<','>' around type.
00749     if (len  > longest_variation)
00750       longest_variation = len;
00751     args_iter++;
00752   }
00753   
00754   args_iter = Args;
00755   while (args_iter->flag != NULL) 
00756   {
00757     int this_variation = 0;
00758     char brackets[2];
00759     if (args_iter->arg_kind == Req) 
00760     {
00761       brackets[0] = '<'; 
00762       brackets[1] = '>';
00763     }
00764     else
00765     {
00766       brackets[0] = '['; 
00767       brackets[1] = ']';
00768     }
00769     cout << "  " << brackets[0]; 
00770 
00771     if (!noFlagP(args_iter->flag)) 
00772     {
00773       cout << "-" << args_iter->flag;
00774         // add one for the '-', as in "-flag"
00775       this_variation = ::strlen(args_iter->flag) + 1;
00776       if (args_iter->uc.type != unionClass::action_t) 
00777       {
00778         cout << " ";
00779         this_variation ++; //  add one for the ' ' in "-flag "
00780       }
00781     }
00782     cout << args_iter->uc.type;
00783     this_variation += ::strlen(unionClass::typeStr(args_iter->uc.type));
00784     if (args_iter->uc.type != unionClass::action_t) 
00785     {
00786         // add two for brackets. '[',']', or '<','>' around type.
00787       this_variation += 2;
00788     }
00789 
00790     cout << brackets[1];
00791     while (this_variation++ < longest_variation)
00792       cout << " ";
00793     cout << "     ";
00794     cout << ((args_iter->description == NULL) ? "" : args_iter->description) 
00795              << '\n';
00796     args_iter++;
00797   }  
00798 }
00799 
00800 
00801 ostream& operator << (ostream& os, unionClass::argType& t) 
00802 {
00803   if (t == unionClass::action_t)
00804     return os;
00805   char brackets[2];
00806     // bool_t arg is always optional. (i.e. -b T, -b F, or -b)
00807   if (t == unionClass::bool_t) 
00808   {  
00809     brackets[0] = '['; 
00810     brackets[1] = ']';
00811   } 
00812   else 
00813   {
00814     brackets[0] = '<'; 
00815     brackets[1] = '>';
00816   }
00817   os << brackets[0] << unionClass::typeStr(t) << brackets[1];
00818   return os;
00819 }
00820 
00821 
00822 char* unionClass::typeStr(unionClass::argType at) 
00823 {
00824   switch (at) 
00825   {
00826     case unionClass::bool_t:    return "bool";
00827     case unionClass::char_t:    return "char";
00828     case unionClass::str_t:     return "string";
00829     case unionClass::int_t:     return "integer";
00830     case unionClass::float_t:   return "float";
00831     case unionClass::double_t:  return "double";
00832     case unionClass::action_t:  return ""; // "ACTION";
00833     default:                    return "error";
00834   }
00835 }
00836 
00837 
00838 ostream& operator << (ostream& os, ARGS* args) 
00839 { 
00840   ARGS* args_iter = args;
00841   while (args_iter->flag != NULL) 
00842   {
00843     os << *args_iter;
00844     args_iter ++;
00845   }
00846   return os; 
00847 }
00848 
00849 
00850 ostream& operator << (ostream& os, ARGS& arg) 
00851 { 
00852   if (!ARGS::noFlagP(arg.flag))
00853     os << arg.flag;
00854   os << ':';
00855   os << unionClass::typeStr(arg.uc.type) << " = ";
00856   switch (arg.uc.type) 
00857   {
00858     case unionClass::bool_t:
00859       os << arg.uc.ptr->boolean; break;
00860     case unionClass::char_t:
00861       os << arg.uc.ptr->ch; break;
00862     case unionClass::str_t: 
00863       os << (arg.uc.ptr->string == NULL ? "" : arg.uc.ptr->string); break;
00864     case unionClass::int_t:
00865       os << arg.uc.ptr->integer; break;
00866     case unionClass::float_t:
00867       os << arg.uc.ptr->single_prec; break;
00868     case unionClass::double_t:
00869       os << arg.uc.ptr->double_prec; break;
00870     case unionClass::action_t:
00871       break;
00872     default:
00873       break;
00874   }
00875   os << ";  // " << ((arg.description == NULL) ? "" : arg.description) 
00876      << '\n';
00877   return os;
00878 }
00879 
00880 
00881   // A typical way one might want to parse their arguments.
00882   // exit the program if any Required arguments are missing or if there is
00883   // some other kind of error.
00884 void ARGS::parse(int argc, char** argv, char*& argsFilep, ostream* prout)
00885 {
00886   pout=prout;
00887   ArgsRetCode rc;
00888   rc = parseFromCommandLine(argc,argv);
00889   if (argsFilep != NULL)
00890     rc = parseFromFile(argsFilep);
00891   if (rc == ARG_MISSING)  // still missing ??
00892     ARGS::printMissing();
00893   if (rc != ARG_OK) 
00894   {
00895     ARGS::usage();
00896     ::exit(1);
00897   }
00898 
00899   if (!pout) return;
00900   ARGS* args_iter = Args;
00901   *pout << "----------------- parameters ----------------" << endl;
00902   while (args_iter->flag != NULL) 
00903   {
00904     switch(args_iter->uc.type) 
00905     {
00906     case unionClass::bool_t: 
00907     {      
00908       *pout << "-" << args_iter->flag << " = "  << args_iter->uc.ptr->boolean 
00909             << endl;
00910     }
00911     break;
00912     case unionClass::char_t: 
00913     {
00914       *pout << "-" << args_iter->flag << " = " << args_iter->uc.ptr->ch<<endl;
00915     }
00916     break;
00917     case unionClass::str_t: 
00918     {
00919       const char* str=(args_iter->uc.ptr->string) ?args_iter->uc.ptr->string:"";
00920       *pout << "-" << args_iter->flag << " = " << str << endl;
00921     }
00922     break;
00923     case unionClass::int_t: 
00924     {
00925       *pout << "-" << args_iter->flag << " = " << args_iter->uc.ptr->integer 
00926             << endl;
00927     }
00928     break;
00929     case unionClass::uint_t: 
00930     {
00931       *pout << "-" << args_iter->flag << " = " << args_iter->uc.ptr->uinteger 
00932             << endl;
00933     }
00934     break;
00935     case unionClass::float_t: 
00936     {
00937       *pout << "-" << args_iter->flag << " = " 
00938             << args_iter->uc.ptr->single_prec << endl;
00939     }
00940     break;
00941     case unionClass::double_t: 
00942     {
00943       *pout << "-" << args_iter->flag << " = " 
00944             << args_iter->uc.ptr->double_prec << endl;
00945     }
00946     break;
00947     default: 
00948     {
00949       cout << "unknown param" << endl;
00950     }
00951     }
00952     args_iter++;
00953   }
00954   *pout << "----------------- end of parameters ----------------" << endl;
00955 
00956 }
00957 
00958 
00959 argsAction::ActionRetCode argsAction::satisfy(char* flag) 
00960 {
00961   ARGS* args_iter;
00962   args_iter = ARGS::findMatch(ARGS::Args,flag);
00963   if (args_iter == NULL || args_iter == (ARGS*)(-1))
00964     return ERR;
00965   ARGS::found[args_iter - ARGS::Args] = true;
00966   return OK;
00967 }
00968 
00969 
00970 argsAction::ActionRetCode
00971 argsAction::setArg(char* flag, unionClass::argType t, unionClass::argU au) 
00972 {
00973   ARGS* args_iter;
00974   args_iter = ARGS::findMatch(ARGS::Args,flag);
00975   if (args_iter == NULL || args_iter == (ARGS*)(-1))
00976     return ERR;
00977   if (args_iter->uc.type != t)
00978     return ERR;
00979   ARGS::found[args_iter - ARGS::Args] = true;
00980   switch(t) 
00981   {
00982     case unionClass::bool_t:
00983       args_iter->uc.ptr->boolean = au.boolean;
00984       if (args_iter->action != NULL)
00985         args_iter->action->act(args_iter->uc.ptr->boolean);
00986       break;
00987     case unionClass::char_t:
00988       args_iter->uc.ptr->ch = au.ch;
00989       if (args_iter->action != NULL)
00990         args_iter->action->act(args_iter->uc.ptr->ch);
00991       break;
00992     case unionClass::str_t:
00993       args_iter->uc.ptr->string = au.string;
00994       if (args_iter->action != NULL)
00995         args_iter->action->act(args_iter->uc.ptr->string);
00996       break;
00997     case unionClass::int_t:
00998       args_iter->uc.ptr->integer = au.integer;
00999       if (args_iter->action != NULL)
01000         args_iter->action->act(args_iter->uc.ptr->integer);
01001       break;
01002     case unionClass::float_t:
01003       args_iter->uc.ptr->single_prec = au.single_prec;
01004       if (args_iter->action != NULL)
01005         args_iter->action->act(args_iter->uc.ptr->single_prec);
01006       break;
01007     case unionClass::double_t:
01008       args_iter->uc.ptr->double_prec = au.double_prec;
01009       if (args_iter->action != NULL)
01010         args_iter->action->act(args_iter->uc.ptr->double_prec);
01011       break;
01012     case unionClass::action_t:
01013       break;
01014     default:
01015       break;
01016   }
01017   return OK;
01018 }
01019 
01020 
01021 argsAction::ActionRetCode argsAction::setArg(char* flag, bool b) 
01022 {
01023   unionClass::argU au;
01024   au.boolean = b;
01025   return setArg(flag,unionClass::bool_t,au);
01026 }
01027 
01028 
01029 argsAction::ActionRetCode argsAction::setArg(char* flag,char c) 
01030 {
01031   unionClass::argU au;
01032   au.ch = c;
01033   return setArg(flag,unionClass::char_t,au);
01034 }
01035 
01036 
01037 argsAction::ActionRetCode argsAction::setArg(char* flag, char* str) 
01038 {
01039   unionClass::argU au;
01040   au.string = str;
01041   return setArg(flag,unionClass::str_t,au);
01042 }
01043 
01044 
01045 argsAction::ActionRetCode argsAction::setArg(char* flag, int i) 
01046 {
01047   unionClass::argU au;
01048   au.integer = i;
01049   return setArg(flag,unionClass::int_t,au);
01050 }
01051 
01052 
01053 argsAction::ActionRetCode argsAction::setArg(char* flag,float f) 
01054 {
01055   unionClass::argU au;
01056   au.single_prec = f;
01057   return setArg(flag,unionClass::float_t,au);
01058 }
01059 
01060 
01061 argsAction::ActionRetCode argsAction::setArg(char* flag,double d) 
01062 {
01063   unionClass::argU au;
01064   au.double_prec = d;
01065   return setArg(flag,unionClass::double_t,au);
01066 }
01067 
01068 
01069 #ifdef MAIN
01070 
01071 class myAction : public argsAction 
01072 {
01073   char* str;
01074  public:
01075   myAction(char *a) { str = a; }
01076 
01077   void act() { cout << "In void myAction::act() :" << str << '\n'; }
01078 
01079   void act(bool& b) 
01080   { 
01081     cout << "In void myAction::act(bool&), b = " << b << ": " << str << '\n'; 
01082   }
01083 
01084   void act(float& f) 
01085   { 
01086     cout << "In void myAction::act(float&), f = " << f << ": " << str << '\n';
01087     setArg("doub",(double)f);
01088   }
01089 };
01090 
01091 
01092 int    bufSize  = 3;
01093 int    buffSize = 3;
01094 char*  bla      = "BARSTR";
01095 bool   truth    = false;
01096 char   chr      = 'c';
01097 float  flt      = 2.3;
01098 double dob      = .4;
01099 bool   toggle1  = false;
01100 bool   toggle2  = true;
01101 
01102 char*  nfstr    = "OSTRTesting";
01103 int    nfint    = 5;
01104 bool   nfbool   = false;
01105 char   nfchar   = 'C';
01106 float  nffloat  = 3.4;
01107 double nfdouble = 4.5;
01108 
01109 char* argsFile  = NULL;
01110 
01111 myAction ma1("toggle 2 action");
01112 myAction ma2("action 1 action");
01113 myAction ma3("set doub action");
01114 
01115 ARGS ARGS::Args[] = 
01116 {
01117  ARGS("buffSize",ARGS::Req, buffSize, "The buffer size"),
01118  ARGS("bufSize", ARGS::Req, bufSize,  "The bufer size"),
01119  ARGS("bla",     ARGS::Opt, bla,      "The bla"),
01120  ARGS("truth",   ARGS::Opt, truth,    "A truth value"),
01121  ARGS("chars",   ARGS::Opt, chr,      "A char"),
01122  ARGS("sing",    ARGS::Opt, flt,      "A single prec", ma3),
01123  ARGS("doub",    ARGS::Req, dob,      "A double prec"),
01124  ARGS("toggle1", ARGS::Tog, toggle1,  "toggle1"),
01125  ARGS("toggle2", ARGS::Tog, toggle2,  "toggle2", ma1),
01126  ARGS("action",  ARGS::Opt, ma2,      "action 1"),
01127  ARGS("argsFile",ARGS::Opt, argsFile, "Arguments file"),
01128 
01129    // Flagless (No-flag) arguments. The order on the command line must be in the
01130    // the same as the order given here. i.e. string first, then int, then
01131    // bool, etc.
01132  ARGS(ARGS::Req, nfstr,    "No flag string"),
01133  ARGS(ARGS::Opt, nfint,    "No flag int"),
01134  ARGS(ARGS::Opt, nfbool,   "No flag bool"),
01135  ARGS(ARGS::Opt, nfchar,   "No flag char"),
01136  ARGS(ARGS::Opt, nffloat,  "No flag float"),
01137  ARGS(ARGS::Opt, nfdouble, "No flag double"),
01138 
01139    // the following END marker must be present.
01140    // ARGS::END
01141  ARGS()
01142 };
01143 
01144 
01145 main(int argc, char* argv[])
01146 {
01147   ARGS::parse(argc,argv,argsFile);
01148   cout << ARGS::Args;
01149 }
01150 
01151 /* 
01152 ** Easy and small template to copy from:
01153 **
01154 
01155 int buffSize = 10;
01156 ARGS ARGS::Args[] = 
01157 {
01158  ARGS("buffSize", ARGS::Req, buffSize, "The buffer size"),
01159  ARGS::END
01160 };
01161 
01162 */
01163 
01164 #endif // def MAIN

Generated on Tue Jan 16 05:30:05 2007 for Alchemy by  doxygen 1.5.1