aboutsummaryrefslogtreecommitdiffstats
path: root/util/argparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/argparse.c')
-rw-r--r--util/argparse.c225
1 files changed, 199 insertions, 26 deletions
diff --git a/util/argparse.c b/util/argparse.c
index 2f733eb4b..10cfd5c1d 100644
--- a/util/argparse.c
+++ b/util/argparse.c
@@ -23,6 +23,7 @@
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <string.h>
#include "util.h"
@@ -124,20 +125,13 @@
*/
-static void set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
static void show_version(void);
-
-int
-arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+static void
+initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
{
- int index;
- int argc;
- char **argv;
- char *s, *s2;
- int i;
-
if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
arg->internal.index = 0;
arg->internal.last = NULL;
@@ -148,20 +142,199 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
if( *arg->argc < 0 )
log_bug("Invalid argument for ArgParse\n");
}
- argc = *arg->argc;
- argv = *arg->argv;
- index = arg->internal.index;
if( arg->err ) { /* last option was erroneous */
- if( arg->r_opt == -3 )
- s = "Missing argument for option \"%.50s\"\n";
- else
- s = "Invalid option \"%.50s\"\n";
- log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+ const char *s;
+
+ if( filename ) {
+ if( arg->r_opt == -6 )
+ s = "%s:%u: argument not expected\n";
+ else if( arg->r_opt == -5 )
+ s = "%s:%u: read error\n";
+ else if( arg->r_opt == -4 )
+ s = "%s:%u: keyword too long\n";
+ else if( arg->r_opt == -3 )
+ s = "%s:%u: missing argument\n";
+ else
+ s = "%s:%u: invalid option\n";
+ log_error(s, filename, *lineno );
+ }
+ else {
+ if( arg->r_opt == -3 )
+ s = "Missing argument for option \"%.50s\"\n";
+ else
+ s = "Invalid option \"%.50s\"\n";
+ log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+ }
if( arg->err != 1 )
exit(2);
arg->err = 0;
}
+}
+
+
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords help, warranty and version
+ * are not valid here.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ */
+int
+optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ char *s, *s2;
+ int state, i, c;
+ int index=0;
+ char keyword[100];
+ char *buffer = NULL;
+ size_t buflen = 0;
+
+ if( !fp ) /* same as arg_parse() in this case */
+ return arg_parse( arg, opts );
+
+ initialize( arg, filename, lineno );
+
+ /* find the next keyword */
+ state = i = 0;
+ for(;;) {
+ c=getc(fp);
+ if( c == '\n' || c== EOF ) {
+ if( c != EOF )
+ ++*lineno;
+ if( state == -1 )
+ break;
+ else if( state == 2 ) {
+ keyword[i] = 0;
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+ break;
+ index = i;
+ arg->r_opt = opts[index].short_opt;
+ if( !opts[index].short_opt )
+ arg->r_opt = -2; /* unknown option */
+ else if( (opts[index].flags & 8) ) /* no optional argument */
+ arg->r_type = 0; /* okay */
+ else /* no required argument */
+ arg->r_opt = -3; /* error */
+ break;
+ }
+ else if( state == 3 ) { /* no argument found */
+ if( !(opts[index].flags & 7) ) /* does not take an argument */
+ arg->r_type = 0; /* okay */
+ else if( (opts[index].flags & 8) ) /* no optional argument */
+ arg->r_type = 0; /* okay */
+ else /* no required argument */
+ arg->r_opt = -3; /* error */
+ break;
+ }
+ else if( state == 4 ) { /* have an argument */
+ if( !(opts[index].flags & 7) ) /* does not take an argument */
+ arg->r_opt = -6; /* error */
+ else {
+ if( !buffer ) {
+ keyword[i] = 0;
+ buffer = m_strdup(keyword);
+ }
+ else
+ buffer[i] = 0;
+
+ if( !set_opt_arg(arg, opts[index].flags, buffer) )
+ m_free(buffer);
+ }
+ break;
+ }
+ else if( c == EOF ) {
+ if( ferror(fp) )
+ arg->r_opt = -5; /* read error */
+ else
+ arg->r_opt = 0; /* eof */
+ break;
+ }
+ state = 0;
+ i = 0;
+ }
+ else if( state == -1 )
+ ; /* skip */
+ else if( !state && isspace(c) )
+ ; /* skip leading white space */
+ else if( !state && c == '#' )
+ state = 1; /* start of a comment */
+ else if( state == 1 )
+ ; /* skip comments */
+ else if( state == 2 && isspace(c) ) {
+ keyword[i] = 0;
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+ break;
+ index = i;
+ arg->r_opt = opts[index].short_opt;
+ if( !opts[index].short_opt ) {
+ arg->r_opt = -2; /* unknown option */
+ state = -1; /* skip rest of line and leave */
+ }
+ else
+ state = 3;
+ }
+ else if( state == 3 ) { /* skip leading spaces of the argument */
+ if( !isspace(c) ) {
+ i = 0;
+ keyword[i] = c;
+ state = 4;
+ }
+ }
+ else if( state == 4 ) { /* collect the argument */
+ if( buffer ) {
+ if( i < buflen-1 )
+ buffer[i++] = c;
+ else {
+ buflen += 50;
+ buffer = m_realloc(buffer, buflen);
+ buffer[i++] = c;
+ }
+ }
+ else if( i < DIM(keyword)-1 )
+ keyword[i++] = c;
+ else {
+ buflen = DIM(keyword)+50;
+ buffer = m_alloc(buflen);
+ memcpy(buffer, keyword, i);
+ buffer[i++] = c;
+ }
+ }
+ else if( i >= DIM(keyword)-1 ) {
+ arg->r_opt = -4; /* keyword to long */
+ state = -1; /* skip rest of line and leave */
+ }
+ else {
+ keyword[i++] = c;
+ state = 2;
+ }
+ }
+
+ return arg->r_opt;
+}
+
+
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int index;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ initialize( arg, NULL, NULL );
+ argc = *arg->argc;
+ argv = *arg->argv;
+ index = arg->internal.index;
if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
argc--; argv++; index++;
@@ -322,7 +495,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
-static void
+static int
set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
{
int base = (flags & 16)? 0 : 10;
@@ -330,17 +503,17 @@ set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
switch( arg->r_type = (flags & 7) ) {
case 1: /* takes int argument */
arg->r.ret_int = (int)strtol(s,NULL,base);
- break;
- default:
- case 2: /* takes string argument */
- arg->r.ret_str = s;
- break;
+ return 0;
case 3: /* takes long argument */
arg->r.ret_long= strtol(s,NULL,base);
- break;
+ return 0;
case 4: /* takes ulong argument */
arg->r.ret_ulong= strtoul(s,NULL,base);
- break;
+ return 0;
+ case 2: /* takes string argument */
+ default:
+ arg->r.ret_str = s;
+ return 1;
}
}