opt.c

Go to the documentation of this file.
00001 /* LIBDGL -- a Directed Graph Library implementation
00002  * Copyright (C) 2002 Roberto Micarelli
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 /* best view tabstop=4
00020  */
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 
00026 #include "opt.h"
00027 
00028 static int _ParseLongOption(GnoOption_s * pOpt, char *pszArg)
00029 {
00030     char *pszLong;
00031     char *pszPar;
00032     char *pszMatch = NULL;
00033     int nret;
00034 
00035 
00036     if (pOpt->pszLong == NULL) {
00037         return 0;
00038     }
00039 
00040     pszLong = strdup(pOpt->pszLong);
00041 
00042     if ((pszPar = strchr(pszArg, '=')) != NULL) {
00043         *pszPar = 0;
00044     }
00045     pszMatch = strdup(pszArg);
00046     if (pszPar)
00047         *pszPar++ = '=';
00048 
00049     if (strcmp(pszLong, pszMatch + 2) == 0) {
00050 
00051         /* * mandatory parameter not found
00052          * */
00053         if (pszPar == NULL) {
00054             nret = -1;
00055             goto free_and_exit;
00056         }
00057 
00058         if (pOpt->ppszValue) {
00059             if (pOpt->ppszValue[0])
00060                 free(pOpt->ppszValue[0]);
00061             pOpt->ppszValue[0] = strdup(pszPar);
00062         }
00063 
00064         nret = 1;
00065         goto free_and_exit;
00066     }
00067 
00068     nret = 0;
00069 
00070   free_and_exit:
00071 
00072     free(pszLong);
00073     free(pszMatch);
00074 
00075     return nret;
00076 }
00077 
00078 static int _ParseLongSwitch(GnoOption_s * pOpt, char *pszArg)
00079 {
00080 
00081     if (pOpt->pszLong == NULL) {
00082         return 0;
00083     }
00084 
00085     if (strcmp(pOpt->pszLong, pszArg + 2) == 0) {
00086         if (pOpt->pfValue)
00087             *pOpt->pfValue = True;
00088 
00089         return 1;
00090     }
00091 
00092     return 0;
00093 }
00094 
00095 
00096 static int _ParseShortOption(GnoOption_s * pOpt, char *pszArg, char *pszPar)
00097 {
00098     char *pszShort;
00099     int ich;
00100 
00101     if (pOpt->pszShort == NULL)
00102         return 0;
00103 
00104     pszShort = strdup(pOpt->pszShort);
00105 
00106     for (ich = 1; pszArg[ich]; ich++) {
00107         if (pszShort[0] == pszArg[ich]) {
00108             if (pszPar == NULL || pszPar[0] == 0) {
00109                 free(pszShort);
00110 
00111                 return -1;
00112             }
00113 
00114             if (pszPar[0] == '-' && pszPar[1] != 0) {
00115                 free(pszShort);
00116 
00117                 return -1;
00118             }
00119 
00120             if (pOpt->ppszValue) {
00121                 if (pOpt->ppszValue[0])
00122                     free(pOpt->ppszValue[0]);
00123                 pOpt->ppszValue[0] = strdup(pszPar);
00124             }
00125 
00126             free(pszShort);
00127 
00128             return 2;
00129         }
00130     }
00131 
00132     free(pszShort);
00133 
00134     return 0;
00135 }
00136 
00137 static int _ParseShortSwitch(GnoOption_s * pOpt, char *pszArg)
00138 {
00139     int ich;
00140 
00141     if (pOpt->pszShort == NULL)
00142         return 0;
00143 
00144     for (ich = 1; pszArg[ich]; ich++) {
00145         if (pOpt->pszShort[0] == pszArg[ich]) {
00146             if (pOpt->pfValue)
00147                 *pOpt->pfValue = True;
00148 
00149             return 1;
00150         }
00151     }
00152 
00153     return 0;
00154 }
00155 
00156 /***********************************************************************
00157  *                              CALLBACKS
00158  **********************************************************************/
00159 
00160 /***********************************************************************
00161  *                              PUBLIC FUNCTIONS
00162  **********************************************************************/
00163 
00164 /*@*--------------------------------------------------------------------
00165  * @func:       GnoParse()
00166  * @descr:      Parse argc, argv against the option array and setup option
00167  *                      values in the array.
00168  * 
00169  * @args:       I:      argc    =       count of argv entries
00170  *                      I:      argv    ->      array of pointer to string
00171  *                      I:      pOpt    ->      option array pointer
00172  *
00173  * @ret:        The number of 'orphan' entries found in the argv.
00174  * @see:        GnoOption_s
00175  *
00176  * @notes:      The argv array will be modified: each argv entry that contains a
00177  *                      recognized option ( '-.' or '--...' ) or each entry recognized as
00178  *                      a parametric option parameter, will be set to NULL.
00179  *                      Thus, at the function return the argv entries not set to NULL are
00180  *                      those of orphan entries (those not related to any option).
00181  *                      The user can then scan argv to find out orphans.
00182  *                      However the number of argv entries will not be altered.
00183  *
00184  *--------------------------------------------------------------------*/
00185 
00186 int GnoParse(int argc, char **argv, GnoOption_s * pOpt)
00187 {
00188     char *pszArgv;
00189     char *pszArgvNxt;
00190     int iArg, iOpt, cOrphan = 0;
00191     int nret, cret;
00192     Boolean fParseError = False;
00193 
00194     /* * this first loop setup default values
00195      * * strdup is used for non-switch options
00196      * * to make life easier when freeing the field
00197      * */
00198     for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
00199         if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
00200             if (pOpt[iOpt].pfValue) {
00201                 pOpt[iOpt].pfValue[0] = pOpt[iOpt].fDef;
00202             }
00203         }
00204         else {
00205             if (pOpt[iOpt].pszDef) {
00206                 if (pOpt[iOpt].ppszValue) {
00207                     pOpt[iOpt].ppszValue[0] = strdup(pOpt[iOpt].pszDef);
00208                 }
00209             }
00210             else {
00211                 if (pOpt[iOpt].ppszValue) {
00212                     pOpt[iOpt].ppszValue[0] = NULL;
00213                 }
00214             }
00215         }
00216     }
00217 
00218     /* * for each arg in argv lookup the matching options
00219      * */
00220     for (iArg = 0, pszArgv = NULL;
00221          iArg < argc && (pszArgv = strdup(argv[iArg])) != NULL;
00222          iArg++, free(pszArgv), pszArgv = NULL) {
00223 
00224         if (pszArgv[0] == '-' && pszArgv[1] == '-' && pszArgv[2]) {     /* long style */
00225             for (iOpt = 0;
00226                  (pOpt[iOpt].pszShort || pOpt[iOpt].pszLong) && argv[iArg];
00227                  iOpt++) {
00228                 if (pOpt[iOpt].pszLong) {
00229                     if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
00230                         nret = _ParseLongSwitch(&pOpt[iOpt], pszArgv);
00231                     }
00232                     else {
00233                         nret = _ParseLongOption(&pOpt[iOpt], pszArgv);
00234                     }
00235 
00236                     if (nret < 0) {
00237                         fprintf(stderr,
00238                                 "parse option: syntax error at <%s>\n",
00239                                 pszArgv);
00240                         fParseError = True;
00241                     }
00242 
00243                     if (nret == 1) {
00244                         argv[iArg] = NULL;
00245                     }
00246                 }
00247             }
00248 
00249             if (argv[iArg]) {
00250                 fprintf(stderr, "parse option: <%s> is out of scope\n",
00251                         pszArgv);
00252                 fParseError = True;
00253             }
00254         }
00255         else if (argv[iArg][0] == '-' && argv[iArg][1]) {       /* short style */
00256             if (iArg + 1 < argc) {
00257                 pszArgvNxt = strdup(argv[iArg + 1]);
00258             }
00259             else {
00260                 pszArgvNxt = NULL;
00261             }
00262 
00263             for (cret = iOpt = 0;
00264                  pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
00265                 if (pOpt[iOpt].pszShort) {
00266                     if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
00267                         nret = _ParseShortSwitch(&pOpt[iOpt], pszArgv);
00268                     }
00269                     else {
00270                         nret =
00271                             _ParseShortOption(&pOpt[iOpt], pszArgv,
00272                                               pszArgvNxt);
00273                     }
00274                     if (nret < 0) {
00275                         fprintf(stderr,
00276                                 "parse option: syntax error at <%s>\n",
00277                                 pszArgv);
00278                         fParseError = True;
00279                     }
00280                     else {
00281                         cret = (nret > cret) ? nret : cret;
00282                     }
00283                 }
00284             }
00285 
00286             if (pszArgvNxt) {
00287                 free(pszArgvNxt);
00288             }
00289 
00290             if (cret == 1) {
00291                 argv[iArg] = NULL;
00292             }
00293             else if (cret == 2) {
00294                 argv[iArg++] = NULL;
00295                 argv[iArg] = NULL;
00296             }
00297 
00298         }
00299         else {
00300             cOrphan++;
00301         }
00302     }
00303 
00304     if (pszArgv)
00305         free(pszArgv);
00306 
00307     return (fParseError == True) ? -1 : cOrphan;
00308 }
00309 
00310 
00311 /*@*--------------------------------------------------------------------
00312  * @func:       GnoFree()
00313  * @descr:      Free resource previously created with a call to GnoParse()
00314  * 
00315  * @args:       I:      pOpt    ->      option array pointer
00316  *
00317  * @see:        GnoOption_s, GnoParse()
00318  *
00319  *--------------------------------------------------------------------*/
00320 void GnoFree(GnoOption_s * pOpt)
00321 {
00322     int iOpt;
00323 
00324     for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
00325         if (pOpt[iOpt].ppszValue) {
00326             if (pOpt[iOpt].ppszValue[0]) {
00327                 free(pOpt[iOpt].ppszValue[0]);
00328                 pOpt[iOpt].ppszValue[0] = NULL;
00329             }
00330         }
00331     }
00332 
00333 }
00334 
00335 /*@*--------------------------------------------------------------------
00336  * @func:       GnoHelp()
00337  * @descr:      Print a brief option's help on the standard error
00338  * 
00339  * @args:       I:      pszHead ->      help header string
00340  *
00341  * @args:       I:      pOpt    ->      option array pointer
00342  *
00343  * @see:        GnoOption_s
00344  *
00345  *--------------------------------------------------------------------*/
00346 void GnoHelp(char *pszHead, GnoOption_s * pOpt)
00347 {
00348     int iOpt;
00349 
00350     fprintf(stderr, "%s\n", (pszHead) ? pszHead : "options");
00351 
00352     for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
00353 
00354         if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
00355             if (pOpt[iOpt].pszShort) {
00356                 fprintf(stderr, "-%s ", pOpt[iOpt].pszShort);
00357             }
00358 
00359             if (pOpt[iOpt].pszLong) {
00360                 fprintf(stderr, "--%s", pOpt[iOpt].pszLong);
00361             }
00362 
00363             fprintf(stderr, "\n\t%s\n", (pOpt[iOpt].pszDescr)
00364                     ? pOpt[iOpt].pszDescr : "No description available.");
00365         }
00366         else {
00367             if (pOpt[iOpt].pszShort) {
00368                 fprintf(stderr, "-%s ", pOpt[iOpt].pszShort);
00369 
00370                 fprintf(stderr, "<value> ");
00371             }
00372 
00373             if (pOpt[iOpt].pszLong) {
00374                 fprintf(stderr, "--%s", pOpt[iOpt].pszLong);
00375 
00376                 fprintf(stderr, "=<value>");
00377             }
00378 
00379             fprintf(stderr, "\n\t%s\n", (pOpt[iOpt].pszDescr)
00380                     ? pOpt[iOpt].pszDescr : "No description available.");
00381         }
00382     }
00383 
00384 }
00385 
00386 /******************************* END OF FILE **************************/

Generated on Thu Jul 16 13:21:17 2009 for GRASS Programmer's Manual by  doxygen 1.5.6