summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwlestes <wlestes>2001-10-17 14:29:52 +0000
committerwlestes <wlestes>2001-10-17 14:29:52 +0000
commit1808505646c1ef6817b02e16c366c2179964835a (patch)
treefdeb7c171900ea19c6b7228da8b1ba7fad1bb194
parent7812a5d7ee0166408403e0dc28e15503d5ef952a (diff)
downloadflex-1808505646c1ef6817b02e16c366c2179964835a.tar.gz
merge latest batch of millaway's changes
-rw-r--r--Makefile.am12
-rw-r--r--buf.c107
-rw-r--r--flex.skl40
-rw-r--r--flex.texi4
-rw-r--r--flexdef.h31
-rw-r--r--main.c736
-rw-r--r--misc.c17
-rw-r--r--options.c78
-rw-r--r--options.h58
-rw-r--r--parse.y4
-rw-r--r--scan.l1
-rw-r--r--scanopt.c803
-rw-r--r--scanopt.h128
13 files changed, 1694 insertions, 325 deletions
diff --git a/Makefile.am b/Makefile.am
index 79795cc..83484cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,7 +57,10 @@ flex_SOURCES = \
skel.c \
sym.c \
tblcmp.c \
- yylex.c
+ yylex.c \
+ options.c \
+ scanopt.c \
+ buf.c
libfl_a_SOURCES = \
libmain.c \
@@ -66,7 +69,9 @@ libfl_a_SOURCES = \
noinst_HEADERS = \
flexdef.h \
parse.h \
- version.h
+ version.h \
+ options.h \
+ scanopt.h
include_HEADERS = \
FlexLexer.h
@@ -111,6 +116,9 @@ parse.o: parse.c flexdef.h config.h
skel.o: skel.c flexdef.h config.h
sym.o: sym.c flexdef.h config.h
tblcmp.o: tblcmp.c flexdef.h config.h
+options.o: options.c options.h scanopt.h flexdef.h config.h
+scanopt.o: scanopt.c scanopt.h flexdef.h config.h
+buf.o: buf.c flexdef.h
#The below recipe for making the ChangeLog will only work if you have a copy of the cvs tree handy so let it fail gracefully.
diff --git a/buf.c b/buf.c
new file mode 100644
index 0000000..ce2c8aa
--- /dev/null
+++ b/buf.c
@@ -0,0 +1,107 @@
+#include "flexdef.h"
+
+/* global buffers. */
+struct Buf userdef_buf; /* for user #definitions triggered by cmd-line. */
+
+
+/* functions for growable buffer. */
+
+/* Appends n characters in str to buf. */
+struct Buf* buf_strnappend (buf,str,n)
+ struct Buf* buf;
+ const char* str;
+ int n;
+{
+ buf_append(buf, str, n+1);
+
+ /* "undo" the '\0' character that buf_append() already copied. */
+ buf->nelts--;
+
+ return buf;
+}
+
+/* Appends characters in str to buf. */
+struct Buf* buf_strappend (buf,str)
+ struct Buf* buf;
+ const char* str;
+{
+ return buf_strnappend(buf, str, strlen(str));
+}
+
+/* appends "#define str def\n" */
+struct Buf* buf_strdefine (buf,str,def)
+ struct Buf* buf;
+ const char* str;
+ const char* def;
+{
+ buf_strappend(buf, "#define ");
+ buf_strappend(buf, " ");
+ buf_strappend(buf, str);
+ buf_strappend(buf, " ");
+ buf_strappend(buf, def);
+ buf_strappend(buf, "\n");
+ return buf;
+}
+
+/* create buf with 0 elements, each of size elem_size. */
+void buf_init(buf, elem_size)
+ struct Buf * buf;
+ size_t elem_size;
+{
+ buf->elts = (void*)0;
+ buf->nelts = 0;
+ buf->elt_size = elem_size;
+ buf->nmax = 0;
+}
+
+/* frees memory */
+void buf_destroy(buf)
+ struct Buf * buf;
+{
+ if(buf && buf->elts)
+ flex_free(buf->elts);
+ buf->elts = (void*)0;
+}
+
+
+/* appends ptr[] to buf, grow if necessary.
+ * n_elem is number of elements in ptr[], NOT bytes.
+ * returns buf.
+ * We grow by mod(512) boundaries.
+ */
+
+struct Buf* buf_append(buf,ptr,n_elem)
+ struct Buf * buf;
+ const void * ptr;
+ int n_elem;
+{
+ int n_alloc=0;
+
+ if (!ptr || n_elem==0)
+ return buf;
+
+ /* May need to alloc more. */
+ if (n_elem + buf->nelts > buf->nmax) {
+
+ /* exact amount needed... */
+ n_alloc = (n_elem + buf->nelts) * buf->elt_size;
+
+ /* ...plus some extra */
+ if (((n_alloc*buf->elt_size)%512) != 0 && buf->elt_size < 512)
+ n_alloc += (512 - ((n_alloc*buf->elt_size)%512)) / buf->elt_size;
+
+ if (!buf->elts)
+ buf->elts = allocate_array( n_alloc , buf->elt_size);
+ else
+ buf->elts = reallocate_array(buf->elts, n_alloc, buf->elt_size);
+
+ buf->nmax = n_alloc;
+ }
+
+ memcpy((char*)buf->elts + buf->nelts*buf->elt_size, ptr, n_elem*buf->elt_size);
+ buf->nelts += n_elem;
+
+ return buf;
+}
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
diff --git a/flex.skl b/flex.skl
index a49f3ba..d9fc54f 100644
--- a/flex.skl
+++ b/flex.skl
@@ -256,9 +256,11 @@ struct yy_buffer_state
};
%- Standard (non-C++) definition
+%c
#ifndef YY_REENTRANT
static YY_BUFFER_STATE yy_current_buffer = 0;
#endif
+%e
%*
/* We provide macros for accessing buffer states in case in the
@@ -271,6 +273,7 @@ static YY_BUFFER_STATE yy_current_buffer = 0;
%- Standard (non-C++) definition
#ifndef YY_REENTRANT
+%c
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
@@ -288,7 +291,7 @@ static int yy_start = 0; /* start state number */
* instead of setting up a fresh yyin. A bit of a hack ...
*/
static int yy_did_buffer_switch_on_eof;
-
+%e
#endif /* end !YY_REENTRANT */
void yyrestart YY_PROTO(( FILE *input_file YY_LAST_ARG ));
@@ -306,9 +309,11 @@ YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str YY_LAST_ARG ));
YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len YY_LAST_ARG ));
%*
+%c
static void *yy_flex_alloc YY_PROTO(( yy_size_t YY_LAST_ARG ));
static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t YY_LAST_ARG ));
static void yy_flex_free YY_PROTO(( void * YY_LAST_ARG ));
+%e
#define yy_new_buffer yy_create_buffer
@@ -333,10 +338,12 @@ static void yy_flex_free YY_PROTO(( void * YY_LAST_ARG ));
%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here
%- Standard (non-C++) definition
+%c
static yy_state_type yy_get_previous_state YY_PROTO(( YY_ONLY_ARG ));
static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state YY_LAST_ARG));
static int yy_get_next_buffer YY_PROTO(( YY_ONLY_ARG ));
static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+%e
%*
/* Done after the current pattern has been matched and before the
@@ -344,16 +351,17 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
*/
#define YY_DO_BEFORE_ACTION \
yytext_ptr = yy_bp; \
-%% code to fiddle yytext and yyleng for yymore() goes here
+%% code to fiddle yytext and yyleng for yymore() goes here \
YY_G(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
-%% code to copy yytext_ptr to yytext[] goes here, if %array
+%% code to copy yytext_ptr to yytext[] goes here, if %array \
YY_G(yy_c_buf_p) = yy_cp;
%*
+%c
%% data tables for the DFA and the user's section 1 definitions go here
-
+%e
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
@@ -406,7 +414,9 @@ struct yy_globals_t
};
+%c
static int yy_init_globals YY_PROTO(( void * ));
+%e
/* This must go here because YYSTYPE and YYLSTYPE are included
* from bison output in section 1.*/
@@ -489,9 +499,11 @@ extern int yywrap YY_PROTO(( YY_ONLY_ARG ));
#endif
%-
+%c
#ifndef YY_NO_UNPUT
static void yyunput YY_PROTO(( int c, char *buf_ptr YY_LAST_ARG));
#endif
+%e
%*
#ifndef yytext_ptr
@@ -504,19 +516,23 @@ static int yy_flex_strlen YY_PROTO(( yyconst char * YY_LAST_ARG));
#ifndef YY_NO_INPUT
%- Standard (non-C++) definition
+%c
#ifdef __cplusplus
static int yyinput YY_PROTO(( YY_ONLY_ARG ));
#else
static int input YY_PROTO(( YY_ONLY_ARG ));
#endif
+%e
%*
#endif
#if YY_STACK_USED
#ifndef YY_REENTRANT
+%c
static int yy_start_stack_ptr = 0;
static int yy_start_stack_depth = 0;
static int *yy_start_stack = 0;
+%e
#endif
#ifndef YY_NO_PUSH_STATE
static void yy_push_state YY_PROTO(( int new_state YY_LAST_ARG));
@@ -572,8 +588,8 @@ YY_MALLOC_DECL
*/
#ifndef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
-%% fread()/read() definition of YY_INPUT goes here unless we're doing C++
-%+ C++ definition
+%% fread()/read() definition of YY_INPUT goes here unless we're doing C++ \
+%+ C++ definition \
if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
YY_FATAL_ERROR( "input in flex scanner failed" );
%*
@@ -634,6 +650,9 @@ YY_MALLOC_DECL
# endif
#endif
+
+extern int yylex YY_PROTO( YY_LEX_ARGS );
+
#define YY_DECL int yylex YY_LEX_ARGS
%+ C++ definition
#define YY_DECL int yyFlexLexer::yylex()
@@ -654,6 +673,7 @@ YY_MALLOC_DECL
%% YY_RULE_SETUP definition goes here
+%c
YY_DECL
{
register yy_state_type yy_current_state;
@@ -859,7 +879,7 @@ do_action: /* This label is used only to access EOF actions. */
} /* end of action switch */
} /* end of scanning one token */
} /* end of yylex */
-
+%e
%+
yyFlexLexer::yyFlexLexer( FLEX_STD istream* arg_yyin, FLEX_STD ostream* arg_yyout )
{
@@ -943,6 +963,7 @@ void yyFlexLexer::LexerOutput( const char* buf, int size )
{
(void) yyout->write( buf, size );
}
+%e
%*
/* yy_get_next_buffer - try to read in a new buffer
@@ -954,6 +975,7 @@ void yyFlexLexer::LexerOutput( const char* buf, int size )
*/
%-
+%c
#ifdef YY_USE_PROTOS
static int yy_get_next_buffer(YY_ONLY_ARG)
#else
@@ -1090,11 +1112,12 @@ int yyFlexLexer::yy_get_next_buffer()
return ret_val;
}
-
+%e
/* yy_get_previous_state - get the state just before the EOB char was reached */
%-
+%c
#ifdef YY_USE_PROTOS
static yy_state_type yy_get_previous_state(YY_ONLY_ARG)
#else
@@ -2074,3 +2097,4 @@ int main()
return 0;
}
#endif
+%e
diff --git a/flex.texi b/flex.texi
index 569e45e..2984cf3 100644
--- a/flex.texi
+++ b/flex.texi
@@ -1913,7 +1913,7 @@ Only users who wish to squeeze every last cycle out of their scanners
need worry about this option. (@pxref{performance}).
@item -c
-is a do-nothing, deprecated option included for POSIX compliance.
+is a do-nothing option included for POSIX compliance.
@item -d
makes the generated scanner run in @dfn{debug} mode. Whenever a pattern
@@ -1963,7 +1963,7 @@ cannot be used with the @samp{-+}, @samp{-f}, @samp{-F}, @samp{-Cf}, or
@code{YY_FLEX_LEX_COMPAT} being @code{#define}'d in the generated scanner.
@item -n
-is another do-nothing, deprecated option included only for
+is another do-nothing option included only for
POSIX compliance.
@item -p
diff --git a/flexdef.h b/flexdef.h
index 0ccc5d9..e046288 100644
--- a/flexdef.h
+++ b/flexdef.h
@@ -31,8 +31,12 @@
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
+#ifndef FLEXDEF_H
+#define FLEXDEF_H 1
+
#include <stdio.h>
#include <ctype.h>
+#include <limits.h>
#include "config.h"
@@ -390,6 +394,7 @@ extern int yymore_really_used, reject_really_used;
* backing_up_file - file to summarize backing-up states to
* infilename - name of input file
* outfilename - name of output file
+ * headerfilename - name of the .h file to generate
* did_outfilename - whether outfilename was explicitly set
* prefix - the prefix used for externally visible names ("yy" by default)
* yyclass - yyFlexLexer subclass to use for YY_DECL
@@ -413,7 +418,7 @@ extern int datapos, dataline, linenum, out_linenum;
extern FILE *skelfile, *yyin, *backing_up_file;
extern const char *skel[];
extern int skel_ind;
-extern char *infilename, *outfilename;
+extern char *infilename, *outfilename, *headerfilename;
extern int did_outfilename;
extern char *prefix, *yyclass;
extern int do_stdinit, use_stdout;
@@ -1022,3 +1027,27 @@ extern void stack1 PROTO((int, int, int, int));
/* from file yylex.c */
extern int yylex PROTO((void));
+
+/* A growable array. See buf.c. */
+struct Buf {
+ void * elts; /* elements. */
+ int nelts; /* number of elements. */
+ size_t elt_size; /* in bytes. */
+ int nmax; /* max capacity of elements. */
+};
+
+extern void buf_init PROTO((struct Buf* buf, size_t elem_size));
+extern void buf_destroy PROTO((struct Buf* buf));
+extern struct Buf* buf_append PROTO((struct Buf* buf, const void* ptr, int n_elem));
+extern struct Buf* buf_strappend PROTO((struct Buf*, const char* str));
+extern struct Buf* buf_strnappend PROTO((struct Buf*, const char* str, int nchars));
+extern struct Buf* buf_strdefine PROTO((struct Buf* buf, const char* str, const char* def));
+
+/* buffer for #define's generated by user-options on cmd line. */
+extern struct Buf userdef_buf;
+
+/* For blocking out code from the header file. */
+#define OUT_BEGIN_CODE() out_str("#ifndef %sIN_HEADER\n",prefix)
+#define OUT_END_CODE() out_str("#endif /* !%sIN_HEADER */\n",prefix);
+
+#endif /* not defined FLEXDEF_H */
diff --git a/main.c b/main.c
index ea1785f..bf7a171 100644
--- a/main.c
+++ b/main.c
@@ -39,6 +39,7 @@ char copyright[] =
#include "flexdef.h"
#include "version.h"
+#include "options.h"
static char flex_version[] = FLEX_VERSION;
@@ -48,8 +49,7 @@ static char flex_version[] = FLEX_VERSION;
void flexinit PROTO((int, char**));
void readin PROTO((void));
void set_up_initial_allocations PROTO((void));
-
-
+static char * basename2 PROTO((char* path, int should_strip_ext));
/* these globals are all defined and commented in flexdef.h */
int printstats, syntaxerror, eofseen, ddebug, trace, nowarn, spprdflt;
@@ -64,7 +64,7 @@ FILE *skelfile = NULL;
int skel_ind = 0;
char *action_array;
int action_size, defs1_offset, prolog_offset, action_offset, action_index;
-char *infilename = NULL, *outfilename = NULL;
+char *infilename = NULL, *outfilename = NULL, *headerfilename = NULL;
int did_outfilename;
char *prefix, *yyclass;
int do_stdinit, use_stdout;
@@ -244,10 +244,10 @@ void check_options()
yytext_is_array = false;
}
- if ( C_plus_plus && (reentrant || reentrant_bison_pure) )
+ if ( C_plus_plus && (reentrant || reentrant_bison_pure) )
flexerror( _( "Options -+ and -R are mutually exclusive." ) );
-
-
+
+
if ( useecs )
{ /* Set up doubly-linked equivalence classes. */
@@ -294,7 +294,7 @@ void check_options()
outfilename = outfile_path;
}
- prev_stdout = freopen( outfilename, "w", stdout );
+ prev_stdout = freopen( outfilename, "w+", stdout );
if ( prev_stdout == NULL )
lerrsf( _( "could not create %s" ), outfilename );
@@ -362,7 +362,7 @@ void check_options()
if ( do_yylineno )
GEN_PREFIX( "lineno" );
-
+
if ( do_yylineno && reentrant)
outn ( "#define YY_USE_LINENO 1");
}
@@ -376,6 +376,10 @@ void check_options()
if ( did_outfilename )
line_directive_out( stdout, 0 );
+ /* Dump the user defined preproc directives. */
+ if (userdef_buf.elts)
+ outn( (char*)(userdef_buf.elts) );
+
skelout();
}
@@ -390,9 +394,13 @@ void flexend( exit_status )
int exit_status;
{
- int tblsiz;
+ static int called_before = -1; /* prevent infinite recursion. */
+ int tblsiz;
int unlink();
+ if( ++called_before )
+ exit( exit_status );
+
if ( skelfile != NULL )
{
if ( ferror( skelfile ) )
@@ -404,6 +412,45 @@ int exit_status;
skelname );
}
+ if ( headerfilename && exit_status == 0 && outfile_created && !ferror(stdout))
+ {
+ /* Copy the file we just wrote to a header file. */
+ #define COPY_SZ 512
+ FILE *header_out;
+ char copybuf[COPY_SZ];
+ int ncopy;
+
+ /* rewind the outfile file. */
+ fflush(stdout);
+ fseek(stdout, 0L, SEEK_SET);
+
+ header_out = fopen(headerfilename, "w");
+ if ( header_out == NULL)
+ lerrsf( _( "could not create %s"), headerfilename );
+
+ fprintf(header_out,
+ "#ifndef %sHEADER_H\n"
+ "#define %sHEADER_H 1\n"
+ "#define %sIN_HEADER 1\n",
+ prefix,prefix,prefix);
+ fflush(header_out);
+
+ while((ncopy=fread(copybuf, 1, COPY_SZ, stdout)) > 0)
+ if ( fwrite(copybuf, 1, ncopy, header_out) <= 0)
+ break;
+
+ fflush(header_out);
+ fprintf(header_out,
+ "\n"
+ "#undef %sIN_HEADER\n"
+ "#endif /* %sHEADER_H */\n",
+ prefix, prefix);
+
+ if ( ferror( header_out ) )
+ lerrsf( _( "error creating header file %s" ), headerfilename);
+ fclose(header_out);
+ }
+
if ( exit_status != 0 && outfile_created )
{
if ( ferror( stdout ) )
@@ -419,6 +466,7 @@ int exit_status;
outfilename );
}
+
if ( backing_up_report && backing_up_file )
{
if ( num_backing_up == 0 )
@@ -461,12 +509,12 @@ int exit_status;
putc( 'p', stderr );
if ( performance_report > 1 )
putc( 'p', stderr );
- if ( spprdflt )
+ if ( spprdflt )
putc( 's', stderr );
- if ( reentrant )
+ if ( reentrant )
{
putc( 'R', stderr );
-
+
if( reentrant_bison_pure )
putc( 'b', stderr );
}
@@ -629,8 +677,9 @@ void flexinit( argc, argv )
int argc;
char **argv;
{
- int i, sawcmpflag;
+ int i, sawcmpflag, rv, optind;
char *arg;
+ scanopt_t sopt;
printstats = syntaxerror = trace = spprdflt = caseins = false;
lex_compat = C_plus_plus = backing_up_report = ddebug = fulltbl = false;
@@ -654,248 +703,288 @@ char **argv;
defs1_offset = prolog_offset = action_offset = action_index = 0;
action_array[0] = '\0';
+ /* Initialize any buffers. */
+ buf_init(&userdef_buf, sizeof(char));
+
/* Enable C++ if program name ends with '+'. */
- program_name = argv[0];
+ program_name = basename2(argv[0],0);
if ( program_name[0] != '\0' &&
program_name[strlen( program_name ) - 1] == '+' )
C_plus_plus = true;
/* read flags */
- for ( --argc, ++argv; argc ; --argc, ++argv )
- {
- arg = argv[0];
-
- /* Stop at first non-option. */
- if ( arg[0] != '-' || arg[1] == '\0' )
- break;
-
- if ( arg[1] == '-' )
- { /* --option */
- if ( ! strcmp( arg, "--help" ) )
- arg = "-h";
-
- else if ( ! strcmp( arg, "--version" ) )
- arg = "-V";
-
- else if ( ! strcmp( arg, "--" ) )
- { /* end of options */
- --argc;
- ++argv;
- break;
- }
- }
-
- for ( i = 1; arg[i] != '\0'; ++i )
- switch ( arg[i] )
- {
- case '+':
- C_plus_plus = true;
- break;
-
- case 'B':
- interactive = false;
- break;
-
- case 'b':
- backing_up_report = true;
- break;
-
- case 'c':
- break;
-
- case 'C':
- if ( i != 1 )
- flexerror(
- _( "-C flag must be given separately" ) );
-
- if ( ! sawcmpflag )
- {
- useecs = false;
- usemecs = false;
- fulltbl = false;
- sawcmpflag = true;
- }
-
- for ( ++i; arg[i] != '\0'; ++i )
- switch ( arg[i] )
- {
- case 'a':
- long_align =
- true;
- break;
-
- case 'e':
- useecs = true;
- break;
-
- case 'F':
- fullspd = true;
- break;
-
- case 'f':
- fulltbl = true;
- break;
-
- case 'm':
- usemecs = true;
- break;
-
- case 'r':
- use_read = true;
- break;
-
- default:
- lerrif(
- _( "unknown -C option '%c'" ),
- (int) arg[i] );
- break;
- }
-
- goto get_next_arg;
-
- case 'd':
- ddebug = true;
- break;
-
- case 'f':
- useecs = usemecs = false;
- use_read = fulltbl = true;
- break;
-
- case 'F':
- useecs = usemecs = false;
- use_read = fullspd = true;
- break;
-
- case '?':
- case 'h':
- usage();
- exit( 0 );
-
- case 'I':
- interactive = true;
- break;
-
- case 'i':
- caseins = true;
- break;
-
- case 'l':
- lex_compat = true;
- break;
-
- case 'L':
- gen_line_dirs = false;
- break;
-
- case 'n':
- /* Stupid do-nothing deprecated
- * option.
- */
- break;
-
- case 'o':
- if ( i != 1 )
- flexerror(
- _( "-o flag must be given separately" ) );
-
- outfilename = arg + i + 1;
- did_outfilename = 1;
- goto get_next_arg;
-
- case 'P':
- if ( i != 1 )
- flexerror(
- _( "-P flag must be given separately" ) );
+ sopt = scanopt_init(flexopts, argc, argv, 0);
+ if (!sopt) {
+ /* This will only happen when flexopts array is altered. */
+ fprintf(stderr,
+ _("Internal error. flexopts are malformed.\n"));
+ exit(1);
+ }
- prefix = arg + i + 1;
- goto get_next_arg;
+ while((rv=scanopt(sopt, &arg, &optind)) != 0){
- case 'p':
- ++performance_report;
- break;
+ if (rv < 0) {
+ /* Scanopt has already printed an option-specific error message. */
+ fprintf( stderr, _( "For usage, try\n\t%s --help\n" ),
+ program_name );
+ exit( 1 );
+ break;
+ }
- case 'R':
- if ( i != 1 )
- flexerror(
- _( "-R flag must be given separately" ) );
+ switch ((enum flexopt_flag_t)rv){
+ case OPT_CPLUSPLUS:
+ C_plus_plus = true;
+ break;
+
+ case OPT_BATCH:
+ interactive = false;
+ break;
+
+ case OPT_BACKUP:
+ backing_up_report = true;
+ break;
+
+ case OPT_DONOTHING:
+ break;
+
+ case OPT_COMPRESSION:
+ if ( ! sawcmpflag )
+ {
+ useecs = false;
+ usemecs = false;
+ fulltbl = false;
+ sawcmpflag = true;
+ }
+
+ for( i=0 ; arg && arg[i] != '\0'; i++)
+ switch ( arg[i] )
+ {
+ case 'a':
+ long_align = true;
+ break;
+
+ case 'e':
+ useecs = true;
+ break;
+
+ case 'F':
+ fullspd = true;
+ break;
+
+ case 'f':
+ fulltbl = true;
+ break;
+
+ case 'm':
+ usemecs = true;
+ break;
+
+ case 'r':
+ use_read = true;
+ break;
+
+ default:
+ lerrif(
+ _( "unknown -C option '%c'" ),
+ (int) arg[i] );
+ break;
+ }
+ break;
+
+ case OPT_DEBUG:
+ ddebug = true;
+ break;
+
+ case OPT_FULL:
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ break;
+
+ case OPT_FAST:
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ break;
+
+ case OPT_HELP:
+ usage();
+ exit( 0 );
+
+ case OPT_INTERACTIVE:
+ interactive = true;
+ break;
+
+ case OPT_CASE_INSENSITIVE:
+ caseins = true;
+ break;
+
+ case OPT_LEX_COMPAT:
+ lex_compat = true;
+ break;
+
+ case OPT_MAIN:
+ buf_strdefine(&userdef_buf, "YY_MAIN", "1");
+ break;
+
+ case OPT_NOLINE:
+ gen_line_dirs = false;
+ break;
+
+ case OPT_OUTFILE:
+ outfilename = arg;
+ did_outfilename = 1;
+ break;
+
+ case OPT_PREFIX:
+ prefix = arg;
+ break;
+
+ case OPT_PERF_REPORT:
+ ++performance_report;
+ break;
+
+ case OPT_REENTRANT_BISON:
reentrant = true;
-
- /* Optional arguments follow -R */
-
- for ( ++i; arg[i] != '\0'; ++i )
- switch ( arg[i] )
- {
- case 'b':
- reentrant_bison_pure = true;
- break;
-
- default:
- lerrif(
- _( "unknown -R option '%c'" ),
- (int) arg[i] );
- break;
- }
- goto get_next_arg;
-
- case 'S':
- if ( i != 1 )
- flexerror(
- _( "-S flag must be given separately" ) );
-
- skelname = arg + i + 1;
- goto get_next_arg;
-
- case 's':
- spprdflt = true;
- break;
-
- case 't':
- use_stdout = true;
- break;
-
- case 'T':
- trace = true;
- break;
-
- case 'v':
- printstats = true;
- break;
-
- case 'V':
- printf( _( "%s version %s\n" ),
- program_name, flex_version );
- exit( 0 );
+ reentrant_bison_pure = true;
+ break;
- case 'w':
- nowarn = true;
- break;
-
- case '7':
- csize = 128;
- break;
-
- case '8':
- csize = CSIZE;
- break;
+ case OPT_REENTRANT:
+ reentrant = true;
- default:
- fprintf( stderr,
- _( "%s: unknown flag '%c'. For usage, try\n\t%s --help\n" ),
- program_name, (int) arg[i],
- program_name );
- exit( 1 );
- }
+ /* Optional 'b' follows -R */
+ if (arg) {
+ if (strcmp(arg,"b")==0)
+ reentrant_bison_pure = true;
+ else
+ lerrif(_( "unknown -R option '%c'" ),(int)arg[i]);
+ }
+ break;
+
+ case OPT_SKEL:
+ skelname = arg;
+ break;
+
+ case OPT_DEFAULT:
+ spprdflt = false;
+ break;
+
+ case OPT_NODEFAULT:
+ spprdflt = true;
+ break;
+
+ case OPT_STDOUT:
+ use_stdout = true;
+ break;
+
+ case OPT_TRACE:
+ trace = true;
+ break;
+
+ case OPT_VERBOSE:
+ printstats = true;
+ break;
+
+ case OPT_VERSION:
+ printf( _( "%s version %s\n" ),
+ program_name, flex_version );
+ exit( 0 );
+
+ case OPT_NOWARN:
+ nowarn = true;
+ break;
+
+ case OPT_7BIT:
+ csize = 128;
+ break;
+
+ case OPT_8BIT:
+ csize = CSIZE;
+ break;
+
+ case OPT_ALIGN:
+ long_align = true;
+ break;
+
+ case OPT_ALWAYS_INTERACTIVE:
+ buf_strdefine(&userdef_buf,"YY_ALWAYS_INTERACTIVE", "1");
+ break;
+
+ case OPT_NEVER_INTERACTIVE:
+ buf_strdefine(&userdef_buf, "YY_NEVER_INTERACTIVE", "1" );
+ break;
+
+ case OPT_ARRAY:
+ yytext_is_array = true;
+ break;
+
+ case OPT_POINTER:
+ yytext_is_array = false;
+ break;
+
+ case OPT_ECS:
+ useecs = true;
+ break;
+
+ case OPT_HEADER:
+ headerfilename = arg;
+ break;
+
+ case OPT_META_ECS:
+ usemecs = true;
+
+
+ case OPT_PREPROCDEFINE:
+ {
+ /* arg is "symbol" or "symbol=definition". */
+ char *def;
+
+ for(def=arg; *def != '\0' && *def!='='; ++def)
+ ;
+
+ buf_strappend(&userdef_buf,"#define ");
+ if (*def=='\0'){
+ buf_strappend(&userdef_buf,arg);
+ buf_strappend(&userdef_buf, " 1\n");
+ }else{
+ buf_strnappend(&userdef_buf, arg,def-arg);
+ buf_strappend(&userdef_buf, " ");
+ buf_strappend(&userdef_buf, def+1);
+ buf_strappend(&userdef_buf, "\n");
+ }
+ }
+ break;
+
+ case OPT_READ:
+ use_read = true;
+ break;
+
+ case OPT_STACK:
+ buf_strdefine(&userdef_buf,"YY_STACK_USED","1");
+ break;
+
+ case OPT_STDINIT:
+ do_stdinit = true;
+ break;
+
+ case OPT_YYCLASS:
+ yyclass = arg;
+ break;
+
+ case OPT_YYLINENO:
+ do_yylineno = true;
+ break;
+
+ case OPT_YYWRAP:
+ do_yywrap = true;
+ break;
+
+ } /* switch */
+ } /* while scanopt() */
+
+ scanopt_destroy(sopt);
- /* Used by -C, -S, -o, and -P flags in lieu of a "continue 2"
- * control.
- */
- get_next_arg: ;
- }
-
- num_input_files = argc;
- input_files = argv;
+ num_input_files = argc - optind;
+ input_files = argv + optind;
set_input_file( num_input_files > 0 ? input_files[0] : NULL );
lastccl = lastsc = lastdfa = lastnfa = 0;
@@ -1040,7 +1129,8 @@ _( "Variable trailing context rules entail a large performance penalty\n" ) );
}
else
- {
+ {
+ OUT_BEGIN_CODE();
/* In reentrant scanner, stdinit is handled in flex.skl. */
if ( do_stdinit )
{
@@ -1065,12 +1155,13 @@ _( "Variable trailing context rules entail a large performance penalty\n" ) );
outn( "#endif" );
}
- else
+ else
{
outn( "#ifndef YY_REENTRANT" );
outn( yy_nostdinit );
outn( "#endif" );
}
+ OUT_END_CODE();
}
if ( fullspd )
@@ -1087,7 +1178,9 @@ _( "Variable trailing context rules entail a large performance penalty\n" ) );
if ( do_yylineno && ! C_plus_plus && ! reentrant )
{
outn( "extern int yylineno;" );
+ OUT_BEGIN_CODE();
outn( "int yylineno = 1;" );
+ OUT_END_CODE();
}
if ( C_plus_plus )
@@ -1102,7 +1195,7 @@ _( "Variable trailing context rules entail a large performance penalty\n" ) );
"\tLexerError( \"yyFlexLexer::yylex invoked but %option yyclass used\" );" );
outn( "\treturn 0;" );
outn( "\t}" );
-
+
out_str( "\n#define YY_DECL int %s::yylex()\n",
yyclass );
}
@@ -1199,72 +1292,95 @@ void set_up_initial_allocations()
}
+/* extracts basename from path, optionally stripping the extension "\.*"
+ * (same concept as /bin/sh `basename`, but different handling of extension). */
+static char * basename2(path, strip_ext)
+ char * path;
+ int strip_ext; /* boolean */
+{
+ char *b, *e=0;
+ b = path;
+ for (b=path; *path; path++)
+ if (*path== '/')
+ b = path+1;
+ else if (*path=='.')
+ e = path;
+
+ if (strip_ext && e && e > b)
+ *e = '\0';
+ return b;
+}
+
void usage()
{
- FILE *f = stdout;
-
- fprintf( f,
-_( "%s [-bcdfhilnpstvwBFILTV78+? -R[b] -C[aefFmr] -ooutput -Pprefix -Sskeleton]\n" ),
- program_name );
- fprintf( f, _( "\t[--help --version] [file ...]\n" ) );
-
- fprintf( f, _( "\t-b generate backing-up information to %s\n" ),
- backing_name );
- fprintf( f, _( "\t-c do-nothing POSIX option\n" ) );
- fprintf( f, _( "\t-d turn on debug mode in generated scanner\n" ) );
- fprintf( f, _( "\t-f generate fast, large scanner\n" ) );
- fprintf( f, _( "\t-h produce this help message\n" ) );
- fprintf( f, _( "\t-i generate case-insensitive scanner\n" ) );
- fprintf( f, _( "\t-l maximal compatibility with original lex\n" ) );
- fprintf( f, _( "\t-n do-nothing POSIX option\n" ) );
- fprintf( f, _( "\t-p generate performance report to stderr\n" ) );
- fprintf( f,
- _( "\t-s suppress default rule to ECHO unmatched text\n" ) );
-
- if ( ! did_outfilename )
- {
- sprintf( outfile_path, outfile_template,
- prefix, C_plus_plus ? "cc" : "c" );
- outfilename = outfile_path;
- }
+ FILE *f = stdout;
+ if ( ! did_outfilename )
+ {
+ sprintf( outfile_path, outfile_template,
+ prefix, C_plus_plus ? "cc" : "c" );
+ outfilename = outfile_path;
+ }
- fprintf( f,
- _( "\t-t write generated scanner on stdout instead of %s\n" ),
- outfilename );
-
- fprintf( f,
- _( "\t-v write summary of scanner statistics to stdout\n" ) );
- fprintf( f, _( "\t-w do not generate warnings\n" ) );
- fprintf( f, _( "\t-B generate batch scanner (opposite of -I)\n" ) );
- fprintf( f,
- _( "\t-F use alternative fast scanner representation\n" ) );
- fprintf( f,
- _( "\t-I generate interactive scanner (opposite of -B)\n" ) );
- fprintf( f, _( "\t-L suppress #line directives in scanner\n" ) );
- fprintf( f, _( "\t-R generate a reentrant C scanner\n" ) );
- fprintf( f,
-_( "\t\t-Rb reentrant scanner is to be called by a bison pure parser.\n" ) );
- fprintf( f, _( "\t-T %s should run in trace mode\n" ), program_name );
- fprintf( f, _( "\t-V report %s version\n" ), program_name );
- fprintf( f, _( "\t-7 generate 7-bit scanner\n" ) );
- fprintf( f, _( "\t-8 generate 8-bit scanner\n" ) );
- fprintf( f, _( "\t-+ generate C++ scanner class\n" ) );
- fprintf( f, _( "\t-? produce this help message\n" ) );
- fprintf( f,
-_( "\t-C specify degree of table compression (default is -Cem):\n" ) );
- fprintf( f,
-_( "\t\t-Ca trade off larger tables for better memory alignment\n" ) );
- fprintf( f, _( "\t\t-Ce construct equivalence classes\n" ) );
- fprintf( f,
-_( "\t\t-Cf do not compress scanner tables; use -f representation\n" ) );
- fprintf( f,
-_( "\t\t-CF do not compress scanner tables; use -F representation\n" ) );
- fprintf( f, _( "\t\t-Cm construct meta-equivalence classes\n" ) );
- fprintf( f,
- _( "\t\t-Cr use read() instead of stdio for scanner input\n" ) );
- fprintf( f, _( "\t-o specify output filename\n" ) );
- fprintf( f, _( "\t-P specify scanner prefix other than \"yy\"\n" ) );
- fprintf( f, _( "\t-S specify skeleton file\n" ) );
- fprintf( f, _( "\t--help produce this help message\n" ) );
- fprintf( f, _( "\t--version report %s version\n" ), program_name );
- }
+ fprintf(f,_( "%s [OPTIONS...] [file...]\n"), program_name);
+ fprintf(f,
+_(
+"Table Compression: (default is -Cem)\n"
+" -Ca, --align trade off larger tables for better memory alignment\n"
+" -Ce, --ecs construct equivalence classes\n"
+" -Cf do not compress tables; use -f representation\n"
+" -CF do not compress tables; use -F representation\n"
+" -Cm, --meta-ecs construct meta-equivalence classes\n"
+" -Cr, --read use read() instead of stdio for scanner input\n"
+" -f, --full generate fast, large scanner. Same as -Cfr\n"
+" -F, --fast use alternate table representation. Same as -CFr\n"
+
+"\n"
+"Debugging:\n"
+" -d, --debug enable debug mode in scanner\n"
+" -b, --backup write backing-up information to %s\n"
+" -p, --perf-report write performance report to stderr\n"
+" -s, --nodefault suppress default rule to ECHO unmatched text\n"
+" -T, --trace %s should run in trace mode\n"
+" -w, --nowarn do not generate warnings\n"
+" -v, --verbose write summary of scanner statistics to stdout\n"
+
+"\n"
+"Files:\n"
+" -o, --outfile=FILE specify output filename\n"
+" -S, --skel=FILE specify skeleton file\n"
+" -t, --stdout write scanner on stdout instead of %s\n"
+" --yyclass=NAME name of C++ class\n"
+
+"\n"
+"Scanner behavior:\n"
+" -7, --7bit generate 7-bit scanner\n"
+" -8, --8bit generate 8-bit scanner\n"
+" -B, --batch generate batch scanner (opposite of -I)\n"
+" -i, --case-insensitive ignore case in patterns\n"
+" -l, --lex-compat maximal compatibility with original lex\n"
+" -I, --interactive generate interactive scanner (opposite of -B)\n"
+" --yylineno track line count in yylineno\n"
+
+"\n"
+"Generated code:\n"
+" -+, --c++ generate C++ scanner class\n"
+" -Dmacro[=defn] #define macro defn (default defn is '1')\n"
+" -L, --noline suppress #line directives in scanner\n"
+" -P, --prefix=STRING use STRING as prefix instead of \"yy\"\n"
+" -R, --reentrant generate a reentrant C scanner\n"
+" -Rb, --reentrant-bison reentrant scanner for bison pure parser.\n"
+
+"\n"
+"Functions:\n"
+" --yywrap call yywrap on EOF\n"
+
+"\n"
+"Miscellaneous:\n"
+" -c do-nothing POSIX option\n"
+" -n do-nothing POSIX option\n"
+" -?\n"
+" -h, --help produce this help message\n"
+" -V, --version report %s version\n"
+), backing_name, program_name, outfile_path, program_name);
+
+}
diff --git a/misc.c b/misc.c
index 7f52950..dc5b6ef 100644
--- a/misc.c
+++ b/misc.c
@@ -34,7 +34,7 @@
#include "flexdef.h"
-
+/* Append "#define defname value\n" to the running buffer. */
void action_define( defname, value )
char *defname;
int value;
@@ -53,6 +53,7 @@ int value;
}
+/* Append "new_text" to the running buffer. */
void add_action( new_text )
char *new_text;
{
@@ -793,6 +794,12 @@ void skelout()
{ /* copy from skel array */
if ( buf[0] == '%' )
{ /* control line */
+ /* print the control line as a comment. */
+ if (buf[strlen(buf)-1]=='\\')
+ out_str("/* %s */\\\n", buf);
+ else
+ out_str("/* %s */\n", buf);
+
switch ( buf[1] )
{
case '%':
@@ -810,6 +817,14 @@ void skelout()
do_copy = 1;
break;
+ case 'c':
+ OUT_BEGIN_CODE();
+ break;
+
+ case 'e':
+ OUT_END_CODE();
+ break;
+
default:
flexfatal(
_( "bad line in skeleton file" ) );
diff --git a/options.c b/options.c
new file mode 100644
index 0000000..26a9039
--- /dev/null
+++ b/options.c
@@ -0,0 +1,78 @@
+#include "options.h"
+
+optspec_t flexopts[] = {
+
+{"--7bit", OPT_7BIT,0},/* Generate 7-bit scanner. */
+{"-7", OPT_7BIT,0},
+{"--8bit", OPT_8BIT,0},/* Generate 8-bit scanner. */
+{"-8", OPT_8BIT,0},
+{"--align", OPT_ALIGN,0},/* Trade off larger tables for better memory alignment. */
+{"--always-interactive",OPT_ALWAYS_INTERACTIVE,0},
+{"--array", OPT_ARRAY,0},
+{"--backup", OPT_BACKUP,0},/* Generate backing-up information to lex.backup. */
+{"-b", OPT_BACKUP,0},
+{"--batch", OPT_BATCH,0},/* Generate batch scanner (opposite of -I). */
+{"-B", OPT_BATCH,0},
+{"--case-insensitive", OPT_CASE_INSENSITIVE,0},/* Generate case-insensitive scanner. */
+{"-i", OPT_CASE_INSENSITIVE,0},
+{"-C[aefFmr]", OPT_COMPRESSION,"Specify degree of table compression (default is -Cem)"},
+{"--c++", OPT_CPLUSPLUS,0},/* Generate C++ scanner class. */
+{"-+", OPT_CPLUSPLUS,0},
+{"--debug", OPT_DEBUG,0},/* Turn on debug mode in generated scanner. */
+{"-d", OPT_DEBUG,0},
+{"--default", OPT_DEFAULT,0},
+{"-c", OPT_DONOTHING,0},/* For POSIX lex compatibility. */
+{"-n", OPT_DONOTHING,0},/* For POSIX lex compatibility. */
+{"--ecs", OPT_ECS,0},/* Construct equivalence classes. */
+{"--fast", OPT_FAST,0},/* Same as -CFr. */
+{"-F", OPT_FAST,0},
+{"--full", OPT_FULL,0},/* Same as -Cfr. */
+{"-f", OPT_FULL,0},
+{"--header[=FILE]", OPT_HEADER,0},
+{"--help", OPT_HELP,0},/* Produce this help message. */
+{"-?", OPT_HELP,0},
+{"-h", OPT_HELP,0},
+{"--interactive", OPT_INTERACTIVE,0},/* Generate interactive scanner (opposite of -B). */
+{"-I", OPT_INTERACTIVE,0},
+{"--lex-compat", OPT_LEX_COMPAT,0},/* Maximal compatibility with original lex. */
+{"-l", OPT_LEX_COMPAT,0},
+{"--main", OPT_MAIN,0}, /* use built-in main() function. */
+{"--meta-ecs", OPT_META_ECS,0},/* Construct meta-equivalence classes. */
+{"--never-interactive", OPT_NEVER_INTERACTIVE,0},
+{"--nodefault", OPT_NODEFAULT,0},/* Suppress default rule to ECHO unmatched text. */
+{"-s", OPT_NODEFAULT,0},
+{"--noline", OPT_NOLINE,0},/* Suppress #line directives in scanner. */
+{"-L", OPT_NOLINE,0},/* Suppress #line directives in scanner. */
+{"--nowarn", OPT_NOWARN,0},/* Suppress warning messages. */
+{"-w", OPT_NOWARN,0},
+{"--outfile=FILE", OPT_OUTFILE,0},/* Write to FILE (default is lex.yy.c) */
+{"-o FILE", OPT_OUTFILE,0},
+{"--perf-report", OPT_PERF_REPORT,0},/* Generate performance report to stderr. */
+{"-p", OPT_PERF_REPORT,0},
+{"--pointer", OPT_POINTER,0},
+{"--prefix=PREFIX", OPT_PREFIX,0},/* Use PREFIX (default is yy) */
+{"-P PREFIX", OPT_PREFIX,0},
+{"-Dmacro", OPT_PREPROCDEFINE,0},/* Define a preprocessor symbol. */
+{"--read", OPT_READ,0},/* Use read(2) instead of stdio. */
+{"--reentrant", OPT_REENTRANT,0},/* Generate a reentrant C scanner. */
+{"-R[b]", OPT_REENTRANT,0},
+{"--reentrant-bison", OPT_REENTRANT_BISON,0},/* Reentrant scanner to be called by a bison pure parser. */
+{"--skel=FILE", OPT_SKEL,0},/* Use skeleton from FILE */
+{"-S FILE", OPT_SKEL,0},
+{"--stack", OPT_STACK,0},
+{"--stdinit", OPT_STDINIT,0},
+{"--stdout", OPT_STDOUT,0},/* Write generated scanner to stdout. */
+{"-t", OPT_STDOUT,0},
+{"--trace", OPT_TRACE,0},/* Flex should run in trace mode. */
+{"-T", OPT_TRACE,0},
+{"--verbose", OPT_VERBOSE,0},/* Write summary of scanner statistics to stdout. */
+{"-v", OPT_VERBOSE,0},
+{"--version", OPT_VERSION,0},/* Report flex version. */
+{"-V", OPT_VERSION,0},
+{"--yyclass=NAME", OPT_YYCLASS,0},
+{"--yylineno", OPT_YYLINENO,0},
+{"--yywrap" , OPT_YYWRAP,0},
+{0,0,0} /* required final NULL entry.*/
+};
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
diff --git a/options.h b/options.h
new file mode 100644
index 0000000..5ee1dc6
--- /dev/null
+++ b/options.h
@@ -0,0 +1,58 @@
+#ifndef OPTIONS_H
+#define OPTIONS_H
+#include "scanopt.h"
+
+extern optspec_t flexopts[];
+
+enum flexopt_flag_t {
+ /* Use positive integers only, since they are return codes for scanopt.
+ * Order is not important. */
+ OPT_7BIT=1,
+ OPT_8BIT,
+ OPT_ALIGN,
+ OPT_ALWAYS_INTERACTIVE,
+ OPT_ARRAY,
+ OPT_BACKUP,
+ OPT_BATCH,
+ OPT_CASE_INSENSITIVE,
+ OPT_COMPRESSION,
+ OPT_CPLUSPLUS,
+ OPT_DEBUG,
+ OPT_DEFAULT,
+ OPT_DONOTHING,
+ OPT_ECS,
+ OPT_FAST,
+ OPT_FULL,
+ OPT_HEADER,
+ OPT_HELP,
+ OPT_INTERACTIVE,
+ OPT_LEX_COMPAT,
+ OPT_MAIN,
+ OPT_META_ECS,
+ OPT_NEVER_INTERACTIVE,
+ OPT_NODEFAULT,
+ OPT_NOLINE,
+ OPT_NOWARN,
+ OPT_OUTFILE,
+ OPT_PERF_REPORT,
+ OPT_POINTER,
+ OPT_PREFIX,
+ OPT_PREPROCDEFINE,
+ OPT_READ,
+ OPT_REENTRANT,
+ OPT_REENTRANT_BISON,
+ OPT_SKEL,
+ OPT_STACK,
+ OPT_STDINIT,
+ OPT_STDOUT,
+ OPT_TRACE,
+ OPT_VERBOSE,
+ OPT_VERSION,
+ OPT_YYCLASS,
+ OPT_YYLINENO,
+ OPT_YYWRAP
+};
+
+#endif
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4 textwidth=0: */
diff --git a/parse.y b/parse.y
index 3a55691..26b646b 100644
--- a/parse.y
+++ b/parse.y
@@ -1,7 +1,7 @@
/* parse.y - parser for flex input */
%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
-%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS
+%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS OPT_HEADER
%token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
%token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
@@ -196,6 +196,8 @@ option : OPT_OUTFILE '=' NAME
{ prefix = copy_string( nmstr ); }
| OPT_YYCLASS '=' NAME
{ yyclass = copy_string( nmstr ); }
+ | OPT_HEADER '=' NAME
+ { headerfilename = copy_string( nmstr ); }
;
sect2 : sect2 scon initforrule flexrule '\n'
diff --git a/scan.l b/scan.l
index 22b2e48..ac58aaf 100644
--- a/scan.l
+++ b/scan.l
@@ -301,6 +301,7 @@ LEXOPT [aceknopr]
outfile return OPT_OUTFILE;
prefix return OPT_PREFIX;
yyclass return OPT_YYCLASS;
+ header return OPT_HEADER;
\"[^"\n]*\" {
strcpy( nmstr, yytext + 1 );
diff --git a/scanopt.c b/scanopt.c
new file mode 100644
index 0000000..0adf512
--- /dev/null
+++ b/scanopt.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 2001, John W. Millaway <john43@astro.temple.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "scanopt.h"
+
+
+/* Internal structures */
+
+#ifdef HAVE_STRCASECMP
+#define STRCASECMP(a,b) strcasecmp(a,b)
+#else
+static int STRCASECMP(a,b)
+ const char* a;
+ const char* b;
+{
+ while(tolower(*a++) == tolower(*b++))
+ ;
+ return b-a;
+}
+#endif
+
+#define ARG_NONE 0x01
+#define ARG_REQ 0x02
+#define ARG_OPT 0x04
+#define IS_LONG 0x08
+
+struct _aux {
+ int flags; /* The above hex flags. */
+ int namelen; /* Length of the actual option word, e.g., "--file[=foo]" is 4 */
+ int printlen; /* Length of entire string, e.g., "--file[=foo]" is 12 */
+};
+
+
+struct _scanopt_t
+{
+ const optspec_t * options; /* List of options. */
+ struct _aux * aux; /* Auxiliary data about options. */
+ int optc; /* Number of options. */
+ int argc; /* Number of args. */
+ char ** argv; /* Array of strings. */
+ int index; /* Used as: argv[index][subscript]. */
+ int subscript;
+ char no_err_msg; /* If true, do not print errors. */
+ char has_long;
+ char has_short;
+};
+
+/* Accessor functions. These WOULD be one-liners, but portability calls. */
+static const char* NAME(s,i)
+ struct _scanopt_t *s; int i;
+{
+ return s->options[i].opt_fmt + ((s->aux[i].flags & IS_LONG)?2:1);
+}
+
+static int PRINTLEN(s,i)
+ struct _scanopt_t *s; int i;
+{
+ return s->aux[i].printlen;
+}
+
+static int RVAL(s,i)
+ struct _scanopt_t *s; int i;
+{
+ return s->options[i].r_val;
+}
+
+static int FLAGS(s,i)
+ struct _scanopt_t *s; int i;
+{
+ return s->aux[i].flags;
+}
+static const char* DESC(s,i)
+ struct _scanopt_t *s; int i;
+{
+ return s->options[i].desc ? s->options[i].desc : "";
+}
+
+#ifndef NO_SCANOPT_USAGE
+static int get_cols()
+{
+ char *env;
+ int cols = 80; /* default */
+
+#ifdef HAVE_NCURSES_H
+ initscr();
+ endwin();
+ if ( COLS > 0 )
+ return COLS;
+#endif
+
+ if((env = getenv("COLUMNS"))!=NULL)
+ cols=atoi(env);
+
+ return cols;
+}
+#endif
+
+/* Macro to check for NULL before assigning a value. */
+#define SAFE_ASSIGN(ptr,val) \
+ do{ \
+ if((ptr)!=NULL) \
+ *(ptr) = val; \
+ }while(0)
+
+/* Macro to assure we reset subscript whenever we adjust s->index.*/
+#define INC_INDEX(s,n) \
+ do{ \
+ (s)->index += (n); \
+ (s)->subscript= 0; \
+ }while(0)
+
+scanopt_t *
+scanopt_init ( options, argc, argv, flags)
+ const optspec_t* options;
+ int argc;
+ char** argv;
+ int flags;
+{
+ int i;
+ struct _scanopt_t * s;
+ s = (struct _scanopt_t*)malloc(sizeof(struct _scanopt_t));
+
+ s->options = options;
+ s->optc = 0;
+ s->argc = argc;
+ s->argv = (char**)argv;
+ s->index = 1;
+ s->subscript = 0;
+ s->no_err_msg = (flags & SCANOPT_NO_ERR_MSG);
+ s->has_long = 0;
+ s->has_short = 0;
+
+ /* Determine option count. (Find entry with all zeros).*/
+ s->optc = 0;
+ while ( options[s->optc].opt_fmt
+ || options[s->optc].r_val
+ || options[s->optc].desc )
+ s->optc++;
+
+ /* Build auxiliary data */
+ s->aux = (struct _aux*)malloc(s->optc * sizeof(struct _aux));
+
+ for (i=0; i < s->optc; i++) {
+ const char * p, *pname;
+ const struct optspec_t* opt;
+ struct _aux * aux;
+
+ opt = s->options + i;
+ aux = s->aux + i;
+
+ aux->flags = ARG_NONE;
+
+ if( opt->opt_fmt[0] == '-' && opt->opt_fmt[1] == '-') {
+ aux->flags |= IS_LONG;
+ pname = opt->opt_fmt + 2;
+ s->has_long = 1;
+ }else{
+ pname = opt->opt_fmt + 1;
+ s->has_short = 1;
+ }
+ aux->printlen = strlen(opt->opt_fmt);
+
+ aux->namelen = 0;
+ for (p=pname+1; *p; p++) {
+ /* detect required arg */
+ if (*p == '=' || isspace(*p) || !(aux->flags & IS_LONG)) {
+ if (aux->namelen==0)
+ aux->namelen = p - pname;
+ aux->flags |= ARG_REQ;
+ aux->flags &= ~ARG_NONE;
+ }
+ /* detect optional arg. This overrides required arg. */
+ if (*p == '[') {
+ if (aux->namelen==0)
+ aux->namelen = p - pname;
+ aux->flags &= ~(ARG_REQ|ARG_NONE);
+ aux->flags |= ARG_OPT;
+ break;
+ }
+ }
+ if (aux->namelen ==0)
+ aux->namelen = p - pname;
+ }
+ return (scanopt_t*)s;
+}
+
+#ifndef NO_SCANOPT_USAGE
+/* these structs are for scanopt_usage(). */
+struct usg_elem {
+ int idx;
+ struct usg_elem * next;
+ struct usg_elem * alias;
+};
+typedef struct usg_elem usg_elem;
+
+
+/* Prints a usage message based on contents of optlist.
+ * Parameters:
+ * scanner - The scanner, already initialized with scanopt_init().
+ * fp - The file stream to write to.
+ * usage - Text to be prepended to option list.
+ * Return: Always returns 0 (zero).
+ * The output looks something like this:
+
+[indent][option, alias1, alias2...][indent][description line1
+ description line2...]
+ */
+int scanopt_usage (scanner,fp,usage)
+ scanopt_t* scanner;
+ FILE* fp;
+ const char* usage;
+{
+ struct _scanopt_t * s;
+ int i,columns,indent=2;
+ usg_elem *byr_val=NULL; /* option indices sorted by r_val */
+ usg_elem *store; /* array of preallocated elements. */
+ int store_idx=0;
+ usg_elem *ue;
+ int maxlen[2] = {0,0};
+ int desccol=0;
+ int print_run=0;
+
+
+ s = (struct _scanopt_t*)scanner;
+
+ if (usage){
+ fprintf(fp,"%s\n",usage);
+ }else{
+ /* Find the basename of argv[0] */
+ const char * p;
+ p = s->argv[0] + strlen(s->argv[0]);
+ while(p != s->argv[0] && *p != '/')
+ --p;
+ if (*p == '/')
+ p++;
+
+ fprintf(fp,"Usage: %s [OPTIONS]...\n", p);
+ }
+ fprintf(fp,"\n");
+
+ /* Sort by r_val and string. Yes, this is O(n*n), but n is small. */
+ store = (usg_elem*)malloc(s->optc*sizeof(usg_elem));
+ for (i=0; i < s->optc; i++) {
+
+ /* grab the next preallocate node. */
+ ue = store + store_idx++;
+ ue->idx = i;
+ ue->next = ue->alias = NULL;
+
+ /* insert into list.*/
+ if( !byr_val )
+ byr_val = ue;
+ else {
+ int found_alias=0;
+ usg_elem **ue_curr, **ptr_if_no_alias=NULL;
+ ue_curr = &byr_val;
+ while (*ue_curr) {
+ if( RVAL(s,(*ue_curr)->idx) == RVAL(s,ue->idx)) {
+ /* push onto the alias list. */
+ ue_curr = &((*ue_curr)->alias);
+ found_alias=1;
+ break;
+ }
+ if( !ptr_if_no_alias
+ && STRCASECMP(NAME(s,(*ue_curr)->idx),NAME(s,ue->idx)) > 0){
+ ptr_if_no_alias = ue_curr;
+ }
+ ue_curr = &((*ue_curr)->next);
+ }
+ if (!found_alias && ptr_if_no_alias)
+ ue_curr = ptr_if_no_alias;
+ ue->next = *ue_curr;
+ *ue_curr = ue;
+ }
+ }
+
+#if 0
+ if(1){
+ printf("ORIGINAL:\n");
+ for(i=0; i < s->optc;i++)
+ printf("%2d: %s\n",i,NAME(s,i));
+ printf("SORTED:\n");
+ ue = byr_val;
+ while(ue) {
+ usg_elem *ue2;
+ printf("%2d: %s\n",ue->idx,NAME(s,ue->idx));
+ for(ue2=ue->alias; ue2; ue2=ue2->next)
+ printf(" +---> %2d: %s\n", ue2->idx, NAME(s,ue2->idx));
+ ue = ue->next;
+ }
+ }
+#endif
+
+ /* Now build each row of output. */
+
+ /* first pass calculate how much room we need. */
+ for (ue=byr_val; ue; ue=ue->next) {
+ usg_elem *ap;
+ int len=0;
+ int nshort=0,nlong=0;
+
+
+#define CALC_LEN(i) do {\
+ if(FLAGS(s,i) & IS_LONG) \
+ len += (nlong++||nshort) ? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
+ else\
+ len += (nshort++||nlong)? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
+ }while(0)
+
+ if(!(FLAGS(s,ue->idx) & IS_LONG))
+ CALC_LEN(ue->idx);
+
+ /* do short aliases first.*/
+ for(ap=ue->alias; ap; ap=ap->next){
+ if(FLAGS(s,ap->idx) & IS_LONG)
+ continue;
+ CALC_LEN(ap->idx);
+ }
+
+ if(FLAGS(s,ue->idx) & IS_LONG)
+ CALC_LEN(ue->idx);
+
+ /* repeat the above loop, this time for long aliases. */
+ for(ap=ue->alias; ap; ap=ap->next){
+ if( !(FLAGS(s,ap->idx) & IS_LONG))
+ continue;
+ CALC_LEN(ap->idx);
+ }
+
+ if(len > maxlen[0])
+ maxlen[0] = len;
+
+ /* It's much easier to calculate length for description column!*/
+ len = strlen(DESC(s,ue->idx));
+ if(len > maxlen[1])
+ maxlen[1] = len;
+ }
+
+ /* Determine how much room we have, and how much we will allocate to each col.
+ * Do not address pathological cases. Output will just be ugly. */
+ columns = get_cols() - 1;
+ if(maxlen[0] + maxlen[1] + indent*2 > columns ) {
+ /* col 0 gets whatever it wants. we'll wrap the desc col. */
+ maxlen[1] = columns - (maxlen[0] + indent*2);
+ if(maxlen[1]< 14) /* 14 is arbitrary lower limit on desc width.*/
+ maxlen[1]= INT_MAX;
+ }
+ desccol = maxlen[0] + indent*2;
+
+#define PRINT_SPACES(fp,n)\
+ do{\
+ int _n;\
+ _n=(n);\
+ while(_n-- > 0)\
+ fputc(' ',(fp));\
+ }while(0)
+
+
+ /* Second pass (same as above loop), this time we print. */
+ /* Sloppy hack: We iterate twice. The first time we print short and long options.
+ The second time we print those lines that have ONLY long options. */
+ while(print_run++ < 2) {
+ for (ue=byr_val; ue; ue=ue->next) {
+ usg_elem *ap;
+ int nwords=0,nchars=0,has_short=0;
+
+/* TODO: get has_short schtick to work */
+ has_short = !(FLAGS(s,ue->idx)&IS_LONG);
+ for(ap=ue->alias; ap; ap=ap->next){
+ if(!(FLAGS(s,ap->idx) & IS_LONG)){
+ has_short=1;
+ break;
+ }
+ }
+ if( (print_run == 1 && !has_short) ||
+ (print_run == 2 && has_short))
+ continue;
+
+ PRINT_SPACES(fp,indent);nchars+=indent;
+
+ /* Print, adding a ", " between aliases. */
+ #define PRINT_IT(i) do{\
+ if(nwords++)\
+ nchars+=fprintf(fp,", ");\
+ nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\
+ }while(0)
+
+ if(!(FLAGS(s,ue->idx) & IS_LONG))
+ PRINT_IT(ue->idx);
+
+ /* print short aliases first.*/
+ for(ap=ue->alias; ap; ap=ap->next){
+ if(!(FLAGS(s,ap->idx) & IS_LONG))
+ PRINT_IT(ap->idx);
+ }
+
+
+ if(FLAGS(s,ue->idx) & IS_LONG)
+ PRINT_IT(ue->idx);
+
+ /* repeat the above loop, this time for long aliases. */
+ for(ap=ue->alias; ap; ap=ap->next){
+ if( FLAGS(s,ap->idx) & IS_LONG)
+ PRINT_IT(ap->idx);
+ }
+
+ /* pad to desccol */
+ PRINT_SPACES(fp, desccol - nchars);
+
+ /* Print description, wrapped to maxlen[1] columns.*/
+ if(1){
+ const char * pstart;
+ pstart = DESC(s,ue->idx);
+ while(1){
+ int n=0;
+ const char * lastws=NULL,*p;
+ p=pstart;
+
+ while(*p && n < maxlen[1] && *p != '\n'){
+ if(isspace(*p) || *p=='-')
+ lastws = p;
+ n++;
+ p++;
+ }
+
+ if(!*p){ /* hit end of desc. done. */
+ fprintf(fp,"%s\n",pstart);
+ break;
+ }
+ else if(*p == '\n'){ /* print everything up to here then wrap.*/
+ fprintf(fp,"%.*s\n",n,pstart);
+ PRINT_SPACES(fp,desccol);
+ pstart = p+1;
+ continue;
+ }
+ else{ /* we hit the edge of the screen. wrap at space if possible.*/
+ if( lastws){
+ fprintf(fp,"%.*s\n",lastws-pstart,pstart);
+ pstart = lastws+1;
+ }else{
+ fprintf(fp,"%.*s\n",n,pstart);
+ pstart = p+1;
+ }
+ PRINT_SPACES(fp,desccol);
+ continue;
+ }
+ }
+ }
+ }
+ }/* end while */
+ free(store);
+ return 0;
+}
+#endif /* no scanopt_usage */
+
+
+static int
+scanopt_err(s,opt_offset,is_short,err)
+ struct _scanopt_t * s;
+ int opt_offset;
+ int is_short;
+ int err;
+{
+ const char *optname="";
+ char optchar[2];
+ const optspec_t * opt=NULL;
+
+ if ( opt_offset >= 0)
+ opt = s->options + opt_offset;
+
+ if ( !s->no_err_msg ) {
+
+ if( s->index > 0 && s->index < s->argc){
+ if (is_short ) {
+ optchar[0] = s->argv[s->index][s->subscript];
+ optchar[1] = '\0';
+ optname = optchar;
+ }else {
+ optname = s->argv[s->index];
+ }
+ }
+
+ fprintf(stderr,"%s: ", s->argv[0]);
+ switch (err) {
+ case SCANOPT_ERR_ARG_NOT_ALLOWED:
+ fprintf(stderr,"option `%s' doesn't allow an argument\n",optname);
+ break;
+ case SCANOPT_ERR_ARG_NOT_FOUND:
+ fprintf(stderr,"option `%s' requires an an argument\n",optname);
+ break;
+ case SCANOPT_ERR_OPT_AMBIGUOUS:
+ fprintf(stderr,"option `%s' is ambiguous\n",optname);
+ break;
+ case SCANOPT_ERR_OPT_UNRECOGNIZED:
+ fprintf(stderr,"Unrecognized option -- `%s'\n",optname);
+ break;
+ default:
+ fprintf(stderr,"Unknown error=(%d)\n",err);
+ break;
+ }
+ }
+ return err;
+}
+
+
+/* Internal. Match str against the regex ^--([^=]+)(=(.*))?
+ * return 1 if *looks* like a long option.
+ * 'str' is the only input argument, the rest of the arguments are output only.
+ * optname will point to str + 2
+ *
+ */
+static int
+matchlongopt(str, optname ,optlen, arg, arglen)
+ char* str;
+ char** optname;
+ int* optlen;
+ char** arg;
+ int* arglen;
+{
+ char * p;
+
+ *optname = *arg = (char*)0;
+ *optlen = *arglen = 0;
+
+ /* Match regex /--./ */
+ p = str;
+ if( p[0]!='-' || p[1]!='-' || !p[2])
+ return 0;
+
+ p += 2;
+ *optname = (char*)p;
+
+ /* find the end of optname */
+ while(*p && *p != '=')
+ ++p;
+
+ *optlen = p - *optname;
+
+ if (!*p)
+ /* an option with no '=...' part. */
+ return 1;
+
+
+ /* We saw an '=' char. The rest of p is the arg.*/
+ p++;
+ *arg = p;
+ while(*p)
+ ++p;
+ *arglen = p - *arg;
+
+ return 1;
+}
+
+
+/* Internal. Look up long or short option by name.
+ * Long options must match a non-ambiguous prefix, or exact match.
+ * Short options must be exact.
+ * Return boolean true if found and no error.
+ * Error stored in err_code or zero if no error. */
+static int
+find_opt (s, lookup_long, optstart, len, err_code, opt_offset)
+ struct _scanopt_t * s;
+ int lookup_long;
+ char * optstart;
+ int len;
+ int *err_code;
+ int* opt_offset;
+{
+ int nmatch=0,lastr_val=0,i;
+ *err_code = 0;
+ *opt_offset = -1;
+
+ if (!optstart)
+ return 0;
+
+ for(i=0; i < s->optc; i++) {
+ char* optname;
+ optname = (char*)(s->options[i].opt_fmt + (lookup_long?2:1));
+
+ if (lookup_long && (s->aux[i].flags & IS_LONG)) {
+ if (len > s->aux[i].namelen)
+ continue;
+
+ if (strncmp(optname, optstart, len) == 0) {
+ nmatch++;
+ *opt_offset = i;
+
+ /* exact match overrides all.*/
+ if(len == s->aux[i].namelen){
+ nmatch=1;
+ break;
+ }
+
+ /* ambiguity is ok between aliases. */
+ if(lastr_val && lastr_val == s->options[i].r_val)
+ nmatch--;
+ lastr_val = s->options[i].r_val;
+ }
+ }
+ else if ( !lookup_long && !(s->aux[i].flags&IS_LONG)) {
+ if (optname[0] == optstart[0]){
+ nmatch++;
+ *opt_offset = i;
+ }
+ }
+ }
+
+ if ( nmatch == 0 ) {
+ *err_code = SCANOPT_ERR_OPT_UNRECOGNIZED;
+ *opt_offset = -1;
+ }
+ else if ( nmatch > 1) {
+ *err_code = SCANOPT_ERR_OPT_AMBIGUOUS;
+ *opt_offset = -1;
+ }
+
+ return *err_code ? 0 : 1;
+}
+
+
+int
+scanopt (svoid, arg, optindex)
+ scanopt_t * svoid;
+ char ** arg;
+ int * optindex;
+{
+ char * optname=NULL, * optarg=NULL, *pstart;
+ int namelen=0, arglen=0;
+ int errcode=0, has_next;
+ const optspec_t * optp;
+ struct _scanopt_t* s;
+ struct _aux * auxp;
+ int is_short;
+ int opt_offset=-1;
+
+ s = (struct _scanopt_t*)svoid;
+
+ /* Normalize return-parameters. */
+ SAFE_ASSIGN(arg,NULL);
+ SAFE_ASSIGN(optindex , s->index);
+
+ if ( s->index >= s->argc )
+ return 0;
+
+ /* pstart always points to the start of our current scan. */
+ pstart = s->argv[s->index] + s->subscript;
+ if ( !pstart )
+ return 0;
+
+ if ( s->subscript == 0 ) {
+
+ /* test for exact match of "--" */
+ if ( pstart[0]=='-' && pstart[1]=='-' && !pstart[2]) {
+ SAFE_ASSIGN(optindex,s->index+1);
+ INC_INDEX(s,1);
+ return 0;
+ }
+
+ /* Match an opt. */
+ if(matchlongopt(pstart,&optname,&namelen,&optarg,&arglen)) {
+
+ /* it LOOKS like an opt, but is it one?! */
+ if( !find_opt(s, 1, optname, namelen, &errcode,&opt_offset)){
+ scanopt_err(s,opt_offset,0,errcode);
+ return errcode;
+ }
+ /* We handle this below. */
+ is_short=0;
+
+ /* Check for short opt. */
+ }else if ( pstart[0] == '-' && pstart[1]) {
+ /* Pass through to below. */
+ is_short=1;
+ s->subscript++;
+ pstart++;
+ }
+
+ else {
+ /* It's not an option. We're done. */
+ return 0;
+ }
+ }
+
+ /* We have to re-check the subscript status because it
+ * may have changed above. */
+
+ if(s->subscript != 0){
+
+ /* we are somewhere in a run of short opts,
+ * e.g., at the 'z' in `tar -xzf` */
+
+ optname = pstart;
+ namelen = 1;
+
+ if(!find_opt(s, 0, pstart, namelen, &errcode,&opt_offset)) {
+ return scanopt_err(s,opt_offset,1,errcode);
+ }
+
+ optarg = pstart+1;
+ arglen = 0;
+ while(optarg[arglen])
+ arglen++;
+
+ if (arglen==0)
+ optarg=NULL;
+ }
+
+ /* At this point, we have a long or short option matched at opt_offset into
+ * the s->options array (and corresponding aux array).
+ * A trailing argument is in {optarg,arglen}, if any.
+ */
+
+ /* Look ahead in argv[] to see if there is something
+ * that we can use as an argument (if needed). */
+ has_next = s->index+1 < s->argc
+ && strcmp("--",s->argv[s->index+1]) != 0;
+
+ optp = s->options + opt_offset;
+ auxp = s->aux + opt_offset;
+
+ /* case: no args allowed */
+ if ( auxp->flags & ARG_NONE) {
+ if ( optarg){
+ scanopt_err(s,opt_offset,is_short,errcode=SCANOPT_ERR_ARG_NOT_ALLOWED);
+ INC_INDEX(s,1);
+ return errcode;
+ }
+ INC_INDEX(s,1);
+ return optp->r_val;
+ }
+
+ /* case: required */
+ if (auxp->flags & ARG_REQ) {
+ if ( !optarg && !has_next)
+ return scanopt_err(s,opt_offset,is_short,SCANOPT_ERR_ARG_NOT_FOUND);
+
+ if (!optarg) {
+ /* Let the next argv element become the argument. */
+ SAFE_ASSIGN(arg,s->argv[s->index+1]);
+ INC_INDEX(s,2);
+ }else{
+ SAFE_ASSIGN(arg,(char*)optarg);
+ INC_INDEX(s,1);
+ }
+ return optp->r_val;
+ }
+
+ /* case: optional */
+ if (auxp->flags & ARG_OPT){
+ SAFE_ASSIGN(arg,optarg);
+ INC_INDEX(s,1);
+ return optp->r_val;
+ }
+
+
+ /* Should not reach here. */
+ return 0;
+}
+
+
+int
+scanopt_destroy(svoid)
+ scanopt_t* svoid;
+{
+ struct _scanopt_t* s;
+ s = (struct _scanopt_t*)svoid;
+ if ( s ) {
+ if (s->aux)
+ free (s->aux);
+ free(s);
+ }
+ return 0;
+}
+
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
diff --git a/scanopt.h b/scanopt.h
new file mode 100644
index 0000000..b6a0638
--- /dev/null
+++ b/scanopt.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2001, John W. Millaway <john43@astro.temple.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SCANOPT_H
+#define SCANOPT_H
+
+#include "flexdef.h"
+
+
+#ifndef NO_SCANOPT_USAGE
+/* Used by scanopt_usage for pretty-printing. */
+#ifdef HAVE_NCURSES_H
+#include <ncurses.h>
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PROTO
+#define PROTO(args) args
+#endif
+
+/* Error codes. */
+enum scanopt_err_t {
+ SCANOPT_ERR_OPT_UNRECOGNIZED = -1, /* Unrecognized option. */
+ SCANOPT_ERR_OPT_AMBIGUOUS = -2, /* It matched more than one option name. */
+ SCANOPT_ERR_ARG_NOT_FOUND= -3, /* The required arg was not found.*/
+ SCANOPT_ERR_ARG_NOT_ALLOWED = -4 /* Option does not take an argument. */
+};
+
+
+/* flags passed to scanopt_init */
+enum scanopt_flag_t {
+ SCANOPT_NO_ERR_MSG = 0x01 /* Suppress printing to stderr. */
+};
+
+/* Specification for a single option. */
+struct optspec_t
+{
+ const char * opt_fmt; /* e.g., "--foo=FILE", "-f FILE", "-n [NUM]" */
+ int r_val; /* Value to be returned by scanopt_ex(). */
+ const char* desc; /* Brief description of this option, or NULL. */
+};
+typedef struct optspec_t optspec_t;
+
+
+/* Used internally by scanopt() to maintain state. */
+/* Never modify these value directly. */
+typedef void * scanopt_t;
+
+
+/* Initializes scanner and checks option list for errors.
+ * Parameters:
+ * options - Array of options.
+ * argc - Same as passed to main().
+ * argv - Same as passed to main(). First element is skipped.
+ * flags - Control behavior.
+ * Return: A malloc'd pointer .
+ */
+scanopt_t* scanopt_init PROTO(( const optspec_t* options,
+ int argc, char** argv, int flags ));
+
+/* Frees memory used by scanner.
+ * Always returns 0. */
+int scanopt_destroy PROTO((scanopt_t* scanner));
+
+#ifndef NO_SCANOPT_USAGE
+/* Prints a usage message based on contents of optlist.
+ * Parameters:
+ * scanner - The scanner, already initialized with scanopt_init().
+ * fp - The file stream to write to.
+ * usage - Text to be prepended to option list. May be NULL.
+ * Return: Always returns 0 (zero).
+ */
+int scanopt_usage PROTO(( scanopt_t* scanner, FILE* fp, const char* usage));
+#endif
+
+/* Scans command-line options in argv[].
+ * Parameters:
+ * scanner - The scanner, already initialized with scanopt_init().
+ * optarg - Return argument, may be NULL.
+ * On success, it points to start of an argument.
+ * optindex - Return argument, may be NULL.
+ * On success or failure, it is the index of this option.
+ * If return is zero, then optindex is the NEXT valid option index.
+ *
+ * Return: > 0 on success. Return value is from optspec_t->rval.
+ * == 0 if at end of options.
+ * < 0 on error (return value is an error code).
+ *
+ */
+int scanopt PROTO(( scanopt_t * scanner, char ** optarg, int * optindex));
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */