Added
This commit is contained in:
499
lang/fortran/comp/parse_args.c
Normal file
499
lang/fortran/comp/parse_args.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/****************************************************************
|
||||
Copyright 1990 by AT&T Bell Laboratories and Bellcore.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the names of AT&T Bell Laboratories or
|
||||
Bellcore or any of their entities not be used in advertising or
|
||||
publicity pertaining to distribution of the software without
|
||||
specific, written prior permission.
|
||||
|
||||
AT&T and Bellcore disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall AT&T or Bellcore be liable for
|
||||
any special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
****************************************************************/
|
||||
|
||||
/* parse_args
|
||||
|
||||
This function will parse command line input into appropriate data
|
||||
structures, output error messages when appropriate and provide some
|
||||
minimal type conversion.
|
||||
|
||||
Input to the function consists of the standard argc,argv
|
||||
values, and a table which directs the parser. Each table entry has the
|
||||
following components:
|
||||
|
||||
prefix -- the (optional) switch character string, e.g. "-" "/" "="
|
||||
switch -- the command string, e.g. "o" "data" "file" "F"
|
||||
flags -- control flags, e.g. CASE_INSENSITIVE, REQUIRED_PREFIX
|
||||
arg_count -- number of arguments this command requires, e.g. 0 for
|
||||
booleans, 1 for filenames, INFINITY for input files
|
||||
result_type -- how to interpret the switch arguments, e.g. STRING,
|
||||
CHAR, FILE, OLD_FILE, NEW_FILE
|
||||
result_ptr -- pointer to storage for the result, be it a table or
|
||||
a string or whatever
|
||||
table_size -- if the arguments fill a table, the maximum number of
|
||||
entries; if there are no arguments, the value to
|
||||
load into the result storage
|
||||
|
||||
Although the table can be used to hold a list of filenames, only
|
||||
scalar values (e.g. pointers) can be stored in the table. No vector
|
||||
processing will be done, only pointers to string storage will be moved.
|
||||
|
||||
An example entry, which could be used to parse input filenames, is:
|
||||
|
||||
"-", "o", 0, oo, OLD_FILE, infilenames, INFILE_TABLE_SIZE
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef NULL
|
||||
/* ANSI C */
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include "parse.h"
|
||||
#include <math.h> /* For atof */
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_INPUT_SIZE 1000
|
||||
|
||||
#define arg_prefix(x) ((x).prefix)
|
||||
#define arg_string(x) ((x).string)
|
||||
#define arg_flags(x) ((x).flags)
|
||||
#define arg_count(x) ((x).count)
|
||||
#define arg_result_type(x) ((x).result_type)
|
||||
#define arg_result_ptr(x) ((x).result_ptr)
|
||||
#define arg_table_size(x) ((x).table_size)
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
typedef int boolean;
|
||||
|
||||
|
||||
char *lower_string (/* char [], char * */);
|
||||
|
||||
static char *this_program = "";
|
||||
|
||||
extern long atol();
|
||||
static int arg_parse (/* char *, arg_info * */);
|
||||
|
||||
|
||||
boolean parse_args (argc, argv, table, entries, others, other_count)
|
||||
int argc;
|
||||
char *argv[];
|
||||
arg_info table[];
|
||||
int entries;
|
||||
char *others[];
|
||||
int other_count;
|
||||
{
|
||||
boolean arg_verify (/* argv, table, entries */);
|
||||
void init_store (/* table, entries */);
|
||||
|
||||
boolean result;
|
||||
|
||||
if (argv)
|
||||
this_program = argv[0];
|
||||
|
||||
/* Check the validity of the table and its parameters */
|
||||
|
||||
result = arg_verify (argv, table, entries);
|
||||
|
||||
/* Initialize the storage values */
|
||||
|
||||
init_store (table, entries);
|
||||
|
||||
if (result) {
|
||||
boolean use_prefix = TRUE;
|
||||
char *argv0;
|
||||
|
||||
argc--;
|
||||
argv0 = *++argv;
|
||||
while (argc) {
|
||||
int index, length;
|
||||
|
||||
index = match_table (*argv, table, entries, use_prefix, &length);
|
||||
if (index < 0) {
|
||||
|
||||
/* The argument doesn't match anything in the table */
|
||||
|
||||
if (others) {
|
||||
|
||||
if (*argv > argv0)
|
||||
*--*argv = '-'; /* complain at invalid flag */
|
||||
|
||||
if (other_count > 0) {
|
||||
*others++ = *argv;
|
||||
other_count--;
|
||||
} else {
|
||||
fprintf (stderr, "%s: too many parameters: ",
|
||||
this_program);
|
||||
fprintf (stderr, "'%s' ignored\n", *argv);
|
||||
} /* else */
|
||||
} /* if (others) */
|
||||
argv0 = *++argv;
|
||||
argc--;
|
||||
} else {
|
||||
|
||||
/* A match was found */
|
||||
|
||||
if (length >= strlen (*argv)) {
|
||||
argc--;
|
||||
argv0 = *++argv;
|
||||
use_prefix = TRUE;
|
||||
} else {
|
||||
(*argv) += length;
|
||||
use_prefix = FALSE;
|
||||
} /* else */
|
||||
|
||||
/* Parse any necessary arguments */
|
||||
|
||||
if (arg_count (table[index]) != P_NO_ARGS) {
|
||||
|
||||
/* Now length will be used to store the number of parsed characters */
|
||||
|
||||
length = arg_parse(*argv, &table[index]);
|
||||
if (*argv == NULL)
|
||||
argc = 0;
|
||||
else if (length >= strlen (*argv)) {
|
||||
argc--;
|
||||
argv0 = *++argv;
|
||||
use_prefix = TRUE;
|
||||
} else {
|
||||
(*argv) += length;
|
||||
use_prefix = FALSE;
|
||||
} /* else */
|
||||
} /* if (argv_count != P_NO_ARGS) */
|
||||
else
|
||||
*arg_result_ptr(table[index]) =
|
||||
arg_table_size(table[index]);
|
||||
} /* else */
|
||||
} /* while (argc) */
|
||||
} /* if (result) */
|
||||
|
||||
return result;
|
||||
} /* parse_args */
|
||||
|
||||
|
||||
boolean arg_verify (argv, table, entries)
|
||||
char *argv[];
|
||||
arg_info table[];
|
||||
int entries;
|
||||
{
|
||||
int i;
|
||||
char *this_program = "";
|
||||
|
||||
if (argv)
|
||||
this_program = argv[0];
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
arg_info *arg = &table[i];
|
||||
|
||||
/* Check the argument flags */
|
||||
|
||||
if (arg_flags (*arg) & ~(P_CASE_INSENSITIVE | P_REQUIRED_PREFIX)) {
|
||||
fprintf (stderr, "%s [arg_verify]: too many ", this_program);
|
||||
fprintf (stderr, "flags in entry %d: '%x' (hex)\n", i,
|
||||
arg_flags (*arg));
|
||||
} /* if */
|
||||
|
||||
/* Check the argument count */
|
||||
|
||||
{ int count = arg_count (*arg);
|
||||
|
||||
if (count != P_NO_ARGS && count != P_ONE_ARG && count !=
|
||||
P_INFINITE_ARGS) {
|
||||
fprintf (stderr, "%s [arg_verify]: invalid ", this_program);
|
||||
fprintf (stderr, "argument count in entry %d: '%d'\n", i,
|
||||
count);
|
||||
} /* if count != P_NO_ARGS ... */
|
||||
|
||||
/* Check the result field; want to be able to store results */
|
||||
|
||||
else
|
||||
if (arg_result_ptr (*arg) == (int *) NULL) {
|
||||
fprintf (stderr, "%s [arg_verify]: ", this_program);
|
||||
fprintf (stderr, "no argument storage given for ");
|
||||
fprintf (stderr, "entry %d\n", i);
|
||||
} /* if arg_result_ptr */
|
||||
}
|
||||
|
||||
/* Check the argument type */
|
||||
|
||||
{ int type = arg_result_type (*arg);
|
||||
|
||||
if (type < P_STRING || type > P_DOUBLE)
|
||||
fprintf(stderr,
|
||||
"%s [arg_verify]: bad arg type in entry %d: '%d'\n",
|
||||
this_program, i, type);
|
||||
}
|
||||
|
||||
/* Check table size */
|
||||
|
||||
{ int size = arg_table_size (*arg);
|
||||
|
||||
if (arg_count (*arg) == P_INFINITE_ARGS && size < 1) {
|
||||
fprintf (stderr, "%s [arg_verify]: bad ", this_program);
|
||||
fprintf (stderr, "table size in entry %d: '%d'\n", i,
|
||||
size);
|
||||
} /* if (arg_count == P_INFINITE_ARGS && size < 1) */
|
||||
}
|
||||
|
||||
} /* for i = 0 */
|
||||
|
||||
return TRUE;
|
||||
} /* arg_verify */
|
||||
|
||||
|
||||
/* match_table -- returns the index of the best entry matching the input,
|
||||
-1 if no match. The best match is the one of longest length which
|
||||
appears lowest in the table. The length of the match will be returned
|
||||
in length ONLY IF a match was found. */
|
||||
|
||||
int match_table (norm_input, table, entries, use_prefix, length)
|
||||
register char *norm_input;
|
||||
arg_info table[];
|
||||
int entries;
|
||||
boolean use_prefix;
|
||||
int *length;
|
||||
{
|
||||
extern int match (/* char *, char *, arg_info *, boolean */);
|
||||
|
||||
char low_input[MAX_INPUT_SIZE];
|
||||
register int i;
|
||||
int best_index = -1, best_length = 0;
|
||||
|
||||
/* FUNCTION BODY */
|
||||
|
||||
(void) lower_string (low_input, norm_input);
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
int this_length = match (norm_input, low_input, &table[i], use_prefix);
|
||||
|
||||
if (this_length > best_length) {
|
||||
best_index = i;
|
||||
best_length = this_length;
|
||||
} /* if (this_length > best_length) */
|
||||
} /* for (i = 0) */
|
||||
|
||||
if (best_index > -1 && length != (int *) NULL)
|
||||
*length = best_length;
|
||||
|
||||
return best_index;
|
||||
} /* match_table */
|
||||
|
||||
|
||||
/* match -- takes an input string and table entry, and returns the length
|
||||
of the longer match.
|
||||
|
||||
0 ==> input doesn't match
|
||||
|
||||
For example:
|
||||
|
||||
INPUT PREFIX STRING RESULT
|
||||
----------------------------------------------------------------------
|
||||
"abcd" "-" "d" 0
|
||||
"-d" "-" "d" 2 (i.e. "-d")
|
||||
"dout" "-" "d" 1 (i.e. "d")
|
||||
"-d" "" "-d" 2 (i.e. "-d")
|
||||
"dd" "d" "d" 2 <= here's the weird one
|
||||
*/
|
||||
|
||||
int match (norm_input, low_input, entry, use_prefix)
|
||||
char *norm_input, *low_input;
|
||||
arg_info *entry;
|
||||
boolean use_prefix;
|
||||
{
|
||||
char *norm_prefix = arg_prefix (*entry);
|
||||
char *norm_string = arg_string (*entry);
|
||||
boolean prefix_match = FALSE, string_match = FALSE;
|
||||
int result = 0;
|
||||
|
||||
/* Buffers for the lowercased versions of the strings being compared.
|
||||
These are used when the switch is to be case insensitive */
|
||||
|
||||
static char low_prefix[MAX_INPUT_SIZE];
|
||||
static char low_string[MAX_INPUT_SIZE];
|
||||
int prefix_length = strlen (norm_prefix);
|
||||
int string_length = strlen (norm_string);
|
||||
|
||||
/* Pointers for the required strings (lowered or nonlowered) */
|
||||
|
||||
register char *input, *prefix, *string;
|
||||
|
||||
/* FUNCTION BODY */
|
||||
|
||||
/* Use the appropriate strings to handle case sensitivity */
|
||||
|
||||
if (arg_flags (*entry) & P_CASE_INSENSITIVE) {
|
||||
input = low_input;
|
||||
prefix = lower_string (low_prefix, norm_prefix);
|
||||
string = lower_string (low_string, norm_string);
|
||||
} else {
|
||||
input = norm_input;
|
||||
prefix = norm_prefix;
|
||||
string = norm_string;
|
||||
} /* else */
|
||||
|
||||
/* First, check the string formed by concatenating the prefix onto the
|
||||
switch string, but only when the prefix is not being ignored */
|
||||
|
||||
if (use_prefix && prefix != NULL && *prefix != '\0')
|
||||
prefix_match = (strncmp (input, prefix, prefix_length) == 0) &&
|
||||
(strncmp (input + prefix_length, string, string_length) == 0);
|
||||
|
||||
/* Next, check just the switch string, if that's allowed */
|
||||
|
||||
if (!use_prefix && (arg_flags (*entry) & P_REQUIRED_PREFIX) == 0)
|
||||
string_match = strncmp (input, string, string_length) == 0;
|
||||
|
||||
if (prefix_match)
|
||||
result = prefix_length + string_length;
|
||||
else if (string_match)
|
||||
result = string_length;
|
||||
|
||||
return result;
|
||||
} /* match */
|
||||
|
||||
|
||||
char *lower_string (dest, src)
|
||||
char *dest, *src;
|
||||
{
|
||||
char *result = dest;
|
||||
register int c;
|
||||
|
||||
if (dest == NULL || src == NULL)
|
||||
result = NULL;
|
||||
else
|
||||
while (*dest++ = (c = *src++) >= 'A' && c <= 'Z' ? tolower(c) : c);
|
||||
|
||||
return result;
|
||||
} /* lower_string */
|
||||
|
||||
|
||||
/* arg_parse -- returns the number of characters parsed for this entry */
|
||||
|
||||
static int arg_parse (str, entry)
|
||||
char *str;
|
||||
arg_info *entry;
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
if (arg_count (*entry) == P_ONE_ARG) {
|
||||
char **store = (char **) arg_result_ptr (*entry);
|
||||
|
||||
length = put_one_arg (arg_result_type (*entry), str, store,
|
||||
arg_prefix (*entry), arg_string (*entry));
|
||||
|
||||
} /* if (arg_count == P_ONE_ARG) */
|
||||
else { /* Must be a table of arguments */
|
||||
char **store = (char **) arg_result_ptr (*entry);
|
||||
|
||||
if (store) {
|
||||
while (*store)
|
||||
store++;
|
||||
|
||||
length = put_one_arg (arg_result_type (*entry), str, store++,
|
||||
arg_prefix (*entry), arg_string (*entry));
|
||||
|
||||
*store = (char *) NULL;
|
||||
} /* if (store) */
|
||||
} /* else */
|
||||
|
||||
return length;
|
||||
} /* arg_parse */
|
||||
|
||||
|
||||
int put_one_arg (type, str, store, prefix, string)
|
||||
int type;
|
||||
char *str;
|
||||
char **store;
|
||||
char *prefix, *string;
|
||||
{
|
||||
int length = 0;
|
||||
long L;
|
||||
|
||||
if (store) {
|
||||
switch (type) {
|
||||
case P_STRING:
|
||||
case P_FILE:
|
||||
case P_OLD_FILE:
|
||||
case P_NEW_FILE:
|
||||
*store = str;
|
||||
if (str == NULL)
|
||||
fprintf (stderr, "%s: Missing argument after '%s%s'\n",
|
||||
this_program, prefix, string);
|
||||
length = str ? strlen (str) : 0;
|
||||
break;
|
||||
case P_CHAR:
|
||||
*((char *) store) = *str;
|
||||
length = 1;
|
||||
break;
|
||||
case P_SHORT:
|
||||
L = atol(str);
|
||||
*(short *)store = (short) L;
|
||||
if (L != *(short *)store)
|
||||
fprintf(stderr,
|
||||
"%s%s parameter '%ld' is not a SHORT INT (truncating to %d)\n",
|
||||
prefix, string, L, *(short *)store);
|
||||
length = strlen (str);
|
||||
break;
|
||||
case P_INT:
|
||||
L = atol(str);
|
||||
*(int *)store = (int)L;
|
||||
if (L != *(int *)store)
|
||||
fprintf(stderr,
|
||||
"%s%s parameter '%ld' is not an INT (truncating to %d)\n",
|
||||
prefix, string, L, *(int *)store);
|
||||
length = strlen (str);
|
||||
break;
|
||||
case P_LONG:
|
||||
*(long *)store = atol(str);
|
||||
length = strlen (str);
|
||||
break;
|
||||
case P_FLOAT:
|
||||
*((float *) store) = (float) atof (str);
|
||||
length = strlen (str);
|
||||
break;
|
||||
case P_DOUBLE:
|
||||
*((double *) store) = (double) atof (str);
|
||||
length = strlen (str);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "put_one_arg: bad type '%d'\n",
|
||||
type);
|
||||
break;
|
||||
} /* switch */
|
||||
} /* if (store) */
|
||||
|
||||
return length;
|
||||
} /* put_one_arg */
|
||||
|
||||
|
||||
void init_store (table, entries)
|
||||
arg_info *table;
|
||||
int entries;
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < entries; index++)
|
||||
if (arg_count (table[index]) == P_INFINITE_ARGS) {
|
||||
char **place = (char **) arg_result_ptr (table[index]);
|
||||
|
||||
if (place)
|
||||
*place = (char *) NULL;
|
||||
} /* if arg_count == P_INFINITE_ARGS */
|
||||
|
||||
} /* init_store */
|
||||
|
||||
Reference in New Issue
Block a user