Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

parse_args.c

Go to the documentation of this file.
00001 #include "stdlib.h"
00002 /****************************************************************
00003 Copyright 1990, 1994-5 by AT&T, Lucent Technologies and Bellcore.
00004 
00005 Permission to use, copy, modify, and distribute this software
00006 and its documentation for any purpose and without fee is hereby
00007 granted, provided that the above copyright notice appear in all
00008 copies and that both that the copyright notice and this
00009 permission notice and warranty disclaimer appear in supporting
00010 documentation, and that the names of AT&T, Bell Laboratories,
00011 Lucent or Bellcore or any of their entities not be used in
00012 advertising or publicity pertaining to distribution of the
00013 software without specific, written prior permission.
00014 
00015 AT&T, Lucent and Bellcore disclaim all warranties with regard to
00016 this software, including all implied warranties of
00017 merchantability and fitness.  In no event shall AT&T, Lucent or
00018 Bellcore be liable for any special, indirect or consequential
00019 damages or any damages whatsoever resulting from loss of use,
00020 data or profits, whether in an action of contract, negligence or
00021 other tortious action, arising out of or in connection with the
00022 use or performance of this software.
00023 ****************************************************************/
00024 
00025 /* parse_args
00026 
00027         This function will parse command line input into appropriate data
00028    structures, output error messages when appropriate and provide some
00029    minimal type conversion.
00030 
00031         Input to the function consists of the standard   argc,argv
00032    values, and a table which directs the parser.  Each table entry has the
00033    following components:
00034 
00035         prefix -- the (optional) switch character string, e.g. "-" "/" "="
00036         switch -- the command string, e.g. "o" "data" "file" "F"
00037         flags -- control flags, e.g.   CASE_INSENSITIVE, REQUIRED_PREFIX
00038         arg_count -- number of arguments this command requires, e.g. 0 for
00039                      booleans, 1 for filenames, INFINITY for input files
00040         result_type -- how to interpret the switch arguments, e.g. STRING,
00041                        CHAR, FILE, OLD_FILE, NEW_FILE
00042         result_ptr -- pointer to storage for the result, be it a table or
00043                       a string or whatever
00044         table_size -- if the arguments fill a table, the maximum number of
00045                       entries; if there are no arguments, the value to
00046                       load into the result storage
00047 
00048         Although the table can be used to hold a list of filenames, only
00049    scalar values (e.g. pointers) can be stored in the table.  No vector
00050    processing will be done, only pointers to string storage will be moved.
00051 
00052         An example entry, which could be used to parse input filenames, is:
00053 
00054         "-", "o", 0, oo, OLD_FILE, infilenames, INFILE_TABLE_SIZE
00055 
00056 */
00057 
00058 #include <stdio.h>
00059 #ifndef NULL
00060 /* ANSI C */
00061 #include <stddef.h>
00062 #endif
00063 #ifdef KR_headers
00064 extern double atof();
00065 #else
00066 #include "stdlib.h"
00067 #include "string.h"
00068 #endif
00069 #include "parse.h"
00070 #include <math.h>            /* For atof */
00071 #include <ctype.h>
00072 
00073 #define MAX_INPUT_SIZE 1000
00074 
00075 #define arg_prefix(x) ((x).prefix)
00076 #define arg_string(x) ((x).string)
00077 #define arg_flags(x) ((x).flags)
00078 #define arg_count(x) ((x).count)
00079 #define arg_result_type(x) ((x).result_type)
00080 #define arg_result_ptr(x) ((x).result_ptr)
00081 #define arg_table_size(x) ((x).table_size)
00082 
00083 #ifndef TRUE
00084 #define TRUE 1
00085 #endif
00086 #ifndef FALSE
00087 #define FALSE 0
00088 #endif
00089 typedef int boolean;
00090 
00091 
00092 static char *this_program = "";
00093 
00094 static int arg_parse Argdcl((char*, arg_info*));
00095 static char *lower_string Argdcl((char*, char*));
00096 static int match Argdcl((char*, char*, arg_info*, boolean));
00097 static int put_one_arg Argdcl((int, char*, char**, char*, char*));
00098 extern int badargs;
00099 
00100 
00101  boolean
00102 #ifdef KR_headers
00103 parse_args(argc, argv, table, entries, others, other_count)
00104         int argc;
00105         char **argv;
00106         arg_info *table;
00107         int entries;
00108         char **others;
00109         int other_count;
00110 #else
00111 parse_args(int argc, char **argv, arg_info *table, int entries, char **others, int other_count)
00112 #endif
00113 {
00114     boolean result;
00115 
00116     if (argv)
00117         this_program = argv[0];
00118 
00119 /* Check the validity of the table and its parameters */
00120 
00121     result = arg_verify (argv, table, entries);
00122 
00123 /* Initialize the storage values */
00124 
00125     init_store (table, entries);
00126 
00127     if (result) {
00128         boolean use_prefix = TRUE;
00129         char *argv0;
00130 
00131         argc--;
00132         argv0 = *++argv;
00133         while (argc) {
00134             int index, length;
00135 
00136             index = match_table (*argv, table, entries, use_prefix, &length);
00137             if (index < 0) {
00138 
00139 /* The argument doesn't match anything in the table */
00140 
00141                 if (others) {
00142 
00143                     if (*argv > argv0)
00144                         *--*argv = '-'; /* complain at invalid flag */
00145 
00146                     if (other_count > 0) {
00147                         *others++ = *argv;
00148                         other_count--;
00149                     } else {
00150                         fprintf (stderr, "%s:  too many parameters: ",
00151                                 this_program);
00152                         fprintf (stderr, "'%s' ignored\n", *argv);
00153                         badargs++;
00154                     } /* else */
00155                 } /* if (others) */
00156                 argv0 = *++argv;
00157                 argc--;
00158             } else {
00159 
00160 /* A match was found */
00161 
00162                 if (length >= strlen (*argv)) {
00163                     argc--;
00164                     argv0 = *++argv;
00165                     use_prefix = TRUE;
00166                 } else {
00167                     (*argv) += length;
00168                     use_prefix = FALSE;
00169                 } /* else */
00170 
00171 /* Parse any necessary arguments */
00172 
00173                 if (arg_count (table[index]) != P_NO_ARGS) {
00174 
00175 /* Now   length   will be used to store the number of parsed characters */
00176 
00177                     length = arg_parse(*argv, &table[index]);
00178                     if (*argv == NULL)
00179                         argc = 0;
00180                     else if (length >= strlen (*argv)) {
00181                         argc--;
00182                         argv0 = *++argv;
00183                         use_prefix = TRUE;
00184                     } else {
00185                         (*argv) += length;
00186                         use_prefix = FALSE;
00187                     } /* else */
00188                 } /* if (argv_count != P_NO_ARGS) */
00189                   else
00190                     *arg_result_ptr(table[index]) =
00191                             arg_table_size(table[index]);
00192             } /* else */
00193         } /* while (argc) */
00194     } /* if (result) */
00195 
00196     return result;
00197 } /* parse_args */
00198 
00199 
00200  boolean
00201 #ifdef KR_headers
00202 arg_verify(argv, table, entries)
00203         char **argv;
00204         arg_info *table;
00205         int entries;
00206 #else
00207 arg_verify(char **argv, arg_info *table, int entries)
00208 #endif
00209 {
00210     int i;
00211     char *this_program = "";
00212 
00213     if (argv)
00214         this_program = argv[0];
00215 
00216     for (i = 0; i < entries; i++) {
00217         arg_info *arg = &table[i];
00218 
00219 /* Check the argument flags */
00220 
00221         if (arg_flags (*arg) & ~(P_CASE_INSENSITIVE | P_REQUIRED_PREFIX)) {
00222             fprintf (stderr, "%s [arg_verify]:  too many ", this_program);
00223             fprintf (stderr, "flags in entry %d:  '%x' (hex)\n", i,
00224                     arg_flags (*arg));
00225             badargs++;
00226         } /* if */
00227 
00228 /* Check the argument count */
00229 
00230         { int count = arg_count (*arg);
00231 
00232             if (count != P_NO_ARGS && count != P_ONE_ARG && count !=
00233                     P_INFINITE_ARGS) {
00234                 fprintf (stderr, "%s [arg_verify]:  invalid ", this_program);
00235                 fprintf (stderr, "argument count in entry %d:  '%d'\n", i,
00236                         count);
00237                 badargs++;
00238             } /* if count != P_NO_ARGS ... */
00239 
00240 /* Check the result field; want to be able to store results */
00241 
00242               else
00243                 if (arg_result_ptr (*arg) == (int *) NULL) {
00244                     fprintf (stderr, "%s [arg_verify]:  ", this_program);
00245                     fprintf (stderr, "no argument storage given for ");
00246                     fprintf (stderr, "entry %d\n", i);
00247                     badargs++;
00248                 } /* if arg_result_ptr */
00249         }
00250 
00251 /* Check the argument type */
00252 
00253         { int type = arg_result_type (*arg);
00254 
00255             if (type < P_STRING || type > P_DOUBLE) {
00256                     fprintf(stderr,
00257                         "%s [arg_verify]:  bad arg type in entry %d:  '%d'\n",
00258                         this_program, i, type);
00259                     badargs++;
00260                     }
00261         }
00262 
00263 /* Check table size */
00264 
00265         { int size = arg_table_size (*arg);
00266 
00267             if (arg_count (*arg) == P_INFINITE_ARGS && size < 1) {
00268                 fprintf (stderr, "%s [arg_verify]:  bad ", this_program);
00269                 fprintf (stderr, "table size in entry %d:  '%d'\n", i,
00270                         size);
00271                 badargs++;
00272             } /* if (arg_count == P_INFINITE_ARGS && size < 1) */
00273         }
00274 
00275     } /* for i = 0 */
00276 
00277     return TRUE;
00278 } /* arg_verify */
00279 
00280 
00281 /* match_table -- returns the index of the best entry matching the input,
00282    -1 if no match.  The best match is the one of longest length which
00283    appears lowest in the table.  The length of the match will be returned
00284    in   length   ONLY IF a match was found.   */
00285 
00286  int
00287 #ifdef KR_headers
00288 match_table(norm_input, table, entries, use_prefix, length)
00289         register char *norm_input;
00290         arg_info *table;
00291         int entries;
00292         boolean use_prefix;
00293         int *length;
00294 #else
00295 match_table(register char *norm_input, arg_info *table, int entries, boolean use_prefix, int *length)
00296 #endif
00297 {
00298     char low_input[MAX_INPUT_SIZE];
00299     register int i;
00300     int best_index = -1, best_length = 0;
00301 
00302 /* FUNCTION BODY */
00303 
00304     (void) lower_string (low_input, norm_input);
00305 
00306     for (i = 0; i < entries; i++) {
00307         int this_length = match(norm_input, low_input, &table[i], use_prefix);
00308 
00309         if (this_length > best_length) {
00310             best_index = i;
00311             best_length = this_length;
00312         } /* if (this_length > best_length) */
00313     } /* for (i = 0) */
00314 
00315     if (best_index > -1 && length != (int *) NULL)
00316         *length = best_length;
00317 
00318     return best_index;
00319 } /* match_table */
00320 
00321 
00322 /* match -- takes an input string and table entry, and returns the length
00323    of the longer match.
00324 
00325         0 ==> input doesn't match
00326 
00327    For example:
00328 
00329         INPUT   PREFIX  STRING  RESULT
00330 ----------------------------------------------------------------------
00331         "abcd"  "-"     "d"     0
00332         "-d"    "-"     "d"     2    (i.e. "-d")
00333         "dout"  "-"     "d"     1    (i.e. "d")
00334         "-d"    ""      "-d"    2    (i.e. "-d")
00335         "dd"    "d"     "d"     2       <= here's the weird one
00336 */
00337 
00338  static int
00339 #ifdef KR_headers
00340 match(norm_input, low_input, entry, use_prefix)
00341         char *norm_input;
00342         char *low_input;
00343         arg_info *entry;
00344         boolean use_prefix;
00345 #else
00346 match(char *norm_input, char *low_input, arg_info *entry, boolean use_prefix)
00347 #endif
00348 {
00349     char *norm_prefix = arg_prefix (*entry);
00350     char *norm_string = arg_string (*entry);
00351     boolean prefix_match = FALSE, string_match = FALSE;
00352     int result = 0;
00353 
00354 /* Buffers for the lowercased versions of the strings being compared.
00355    These are used when the switch is to be case insensitive */
00356 
00357     static char low_prefix[MAX_INPUT_SIZE];
00358     static char low_string[MAX_INPUT_SIZE];
00359     int prefix_length = strlen (norm_prefix);
00360     int string_length = strlen (norm_string);
00361 
00362 /* Pointers for the required strings (lowered or nonlowered) */
00363 
00364     register char *input, *prefix, *string;
00365 
00366 /* FUNCTION BODY */
00367 
00368 /* Use the appropriate strings to handle case sensitivity */
00369 
00370     if (arg_flags (*entry) & P_CASE_INSENSITIVE) {
00371         input = low_input;
00372         prefix = lower_string (low_prefix, norm_prefix);
00373         string = lower_string (low_string, norm_string);
00374     } else {
00375         input = norm_input;
00376         prefix = norm_prefix;
00377         string = norm_string;
00378     } /* else */
00379 
00380 /* First, check the string formed by concatenating the prefix onto the
00381    switch string, but only when the prefix is not being ignored */
00382 
00383     if (use_prefix && prefix != NULL && *prefix != '\0')
00384          prefix_match = (strncmp (input, prefix, prefix_length) == 0) &&
00385                 (strncmp (input + prefix_length, string, string_length) == 0);
00386 
00387 /* Next, check just the switch string, if that's allowed */
00388 
00389     if (!use_prefix && (arg_flags (*entry) & P_REQUIRED_PREFIX) == 0)
00390         string_match = strncmp (input, string, string_length) == 0;
00391 
00392     if (prefix_match)
00393         result = prefix_length + string_length;
00394     else if (string_match)
00395         result = string_length;
00396 
00397     return result;
00398 } /* match */
00399 
00400 
00401  static char *
00402 #ifdef KR_headers
00403 lower_string(dest, src)
00404         char *dest;
00405         char *src;
00406 #else
00407 lower_string(char *dest, char *src)
00408 #endif
00409 {
00410     char *result = dest;
00411     register int c;
00412 
00413     if (dest == NULL || src == NULL)
00414         result = NULL;
00415     else
00416         while (*dest++ = (c = *src++) >= 'A' && c <= 'Z' ? tolower(c) : c);
00417 
00418     return result;
00419 } /* lower_string */
00420 
00421 
00422 /* arg_parse -- returns the number of characters parsed for this entry */
00423 
00424  static int
00425 #ifdef KR_headers
00426 arg_parse(str, entry)
00427         char *str;
00428         arg_info *entry;
00429 #else
00430 arg_parse(char *str, arg_info *entry)
00431 #endif
00432 {
00433     int length = 0;
00434 
00435     if (arg_count (*entry) == P_ONE_ARG) {
00436         char **store = (char **) arg_result_ptr (*entry);
00437 
00438         length = put_one_arg (arg_result_type (*entry), str, store,
00439                 arg_prefix (*entry), arg_string (*entry));
00440 
00441     } /* if (arg_count == P_ONE_ARG) */
00442       else { /* Must be a table of arguments */
00443         char **store = (char **) arg_result_ptr (*entry);
00444 
00445         if (store) {
00446             while (*store)
00447                 store++;
00448 
00449             length = put_one_arg(arg_result_type (*entry), str, store++,
00450                     arg_prefix (*entry), arg_string (*entry));
00451 
00452             *store = (char *) NULL;
00453         } /* if (store) */
00454     } /* else */
00455 
00456     return length;
00457 } /* arg_parse */
00458 
00459 
00460  static int
00461 #ifdef KR_headers
00462 put_one_arg(type, str, store, prefix, string)
00463         int type;
00464         char *str;
00465         char **store;
00466         char *prefix;
00467         char *string;
00468 #else
00469 put_one_arg(int type, char *str, char **store, char *prefix, char *string)
00470 #endif
00471 {
00472     int length = 0;
00473     long L;
00474 
00475     if (store) {
00476         switch (type) {
00477             case P_STRING:
00478             case P_FILE:
00479             case P_OLD_FILE:
00480             case P_NEW_FILE:
00481                 if (str == NULL) {
00482                         fprintf(stderr, "%s: Missing argument after '%s%s'\n",
00483                                 this_program, prefix, string);
00484                         length = 0;
00485                         badargs++;
00486                         }
00487                 else
00488                         length = strlen(*store = str);
00489                 break;
00490             case P_CHAR:
00491                 *((char *) store) = *str;
00492                 length = 1;
00493                 break;
00494             case P_SHORT:
00495                 L = atol(str);
00496                 *(short *)store = (short) L;
00497                 if (L != *(short *)store) {
00498                     fprintf(stderr,
00499         "%s%s parameter '%ld' is not a SHORT INT (truncating to %d)\n",
00500                             prefix, string, L, *(short *)store);
00501                     badargs++;
00502                     }
00503                 length = strlen (str);
00504                 break;
00505             case P_INT:
00506                 L = atol(str);
00507                 *(int *)store = (int)L;
00508                 if (L != *(int *)store) {
00509                     fprintf(stderr,
00510         "%s%s parameter '%ld' is not an INT (truncating to %d)\n",
00511                             prefix, string, L, *(int *)store);
00512                     badargs++;
00513                     }
00514                 length = strlen (str);
00515                 break;
00516             case P_LONG:
00517                 *(long *)store = atol(str);
00518                 length = strlen (str);
00519                 break;
00520             case P_FLOAT:
00521                 *((float *) store) = (float) atof(str);
00522                 length = strlen (str);
00523                 break;
00524             case P_DOUBLE:
00525                 *((double *) store) = (double) atof(str);
00526                 length = strlen (str);
00527                 break;
00528             default:
00529                 fprintf (stderr, "put_one_arg:  bad type '%d'\n", type);
00530                 badargs++;
00531                 break;
00532         } /* switch */
00533     } /* if (store) */
00534 
00535     return length;
00536 } /* put_one_arg */
00537 
00538 
00539  void
00540 #ifdef KR_headers
00541 init_store(table, entries)
00542         arg_info *table;
00543         int entries;
00544 #else
00545 init_store(arg_info *table, int entries)
00546 #endif
00547 {
00548     int index;
00549 
00550     for (index = 0; index < entries; index++)
00551         if (arg_count (table[index]) == P_INFINITE_ARGS) {
00552             char **place = (char **) arg_result_ptr (table[index]);
00553 
00554             if (place)
00555                 *place = (char *) NULL;
00556         } /* if arg_count == P_INFINITE_ARGS */
00557 
00558 } /* init_store */
 

Powered by Plone

This site conforms to the following standards: