]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
gnutls-cli, gnutls-cli-debug and srptool use libopts.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 17 Jan 2012 18:50:27 +0000 (19:50 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 21 Jan 2012 00:06:45 +0000 (01:06 +0100)
78 files changed:
.gitignore
Makefile.am
configure.ac
doc/manpages/Makefile.am
doc/manpages/gnutls-cli.1 [deleted file]
doc/manpages/srptool.1
libopts/COPYING.gplv3 [new file with mode: 0644]
libopts/COPYING.lgplv3 [new file with mode: 0644]
libopts/COPYING.mbsd [new file with mode: 0644]
libopts/MakeDefs.inc [new file with mode: 0644]
libopts/Makefile.am [new file with mode: 0644]
libopts/README [new file with mode: 0644]
libopts/ag-char-map.h [new file with mode: 0644]
libopts/autoopts.c [new file with mode: 0644]
libopts/autoopts.h [new file with mode: 0644]
libopts/autoopts/options.h [new file with mode: 0644]
libopts/autoopts/project.h [new file with mode: 0644]
libopts/autoopts/usage-txt.h [new file with mode: 0644]
libopts/boolean.c [new file with mode: 0644]
libopts/check.c [new file with mode: 0644]
libopts/compat/compat.h [new file with mode: 0644]
libopts/compat/pathfind.c [new file with mode: 0644]
libopts/compat/snprintf.c [new file with mode: 0644]
libopts/compat/strchr.c [new file with mode: 0644]
libopts/compat/strdup.c [new file with mode: 0644]
libopts/compat/windows-config.h [new file with mode: 0644]
libopts/configfile.c [new file with mode: 0644]
libopts/cook.c [new file with mode: 0644]
libopts/enum.c [new file with mode: 0644]
libopts/env.c [new file with mode: 0644]
libopts/file.c [new file with mode: 0644]
libopts/find.c [new file with mode: 0644]
libopts/genshell.c [new file with mode: 0644]
libopts/genshell.h [new file with mode: 0644]
libopts/libopts.c [new file with mode: 0644]
libopts/load.c [new file with mode: 0644]
libopts/makeshell.c [new file with mode: 0644]
libopts/nested.c [new file with mode: 0644]
libopts/numeric.c [new file with mode: 0644]
libopts/parse-duration.c [new file with mode: 0644]
libopts/parse-duration.h [new file with mode: 0644]
libopts/pgusage.c [new file with mode: 0644]
libopts/proto.h [new file with mode: 0644]
libopts/putshell.c [new file with mode: 0644]
libopts/reset.c [new file with mode: 0644]
libopts/restore.c [new file with mode: 0644]
libopts/save.c [new file with mode: 0644]
libopts/sort.c [new file with mode: 0644]
libopts/stack.c [new file with mode: 0644]
libopts/streqvcmp.c [new file with mode: 0644]
libopts/text_mmap.c [new file with mode: 0644]
libopts/time.c [new file with mode: 0644]
libopts/tokenize.c [new file with mode: 0644]
libopts/usage.c [new file with mode: 0644]
libopts/value-type.c [new file with mode: 0644]
libopts/value-type.h [new file with mode: 0644]
libopts/version.c [new file with mode: 0644]
libopts/xat-attribute.c [new file with mode: 0644]
libopts/xat-attribute.h [new file with mode: 0644]
m4/libopts.m4 [new file with mode: 0644]
m4/liboptschk.m4 [new file with mode: 0644]
src/Makefile.am
src/cli-args.c [new file with mode: 0644]
src/cli-args.def.in [new file with mode: 0644]
src/cli-args.h [new file with mode: 0644]
src/cli-debug-args.def.in [new file with mode: 0644]
src/cli.c
src/cli.gaa [deleted file]
src/common.h
src/srptool-args.c [new file with mode: 0644]
src/srptool-args.def.in [new file with mode: 0644]
src/srptool-args.h [new file with mode: 0644]
src/srptool.c
src/srptool.gaa [deleted file]
src/tls_test-gaa.c [deleted file]
src/tls_test-gaa.h [deleted file]
src/tls_test.c
src/tls_test.gaa [deleted file]

index 094061481814c012e4367481e36664292a1f4122..44db8bf242c718beb7925904f05ac1689e9991a2 100644 (file)
@@ -421,6 +421,8 @@ po/quot.sed
 po/remove-potcdate.sed
 po/remove-potcdate.sin
 po/stamp-po
+src/cli-args.def
+src/srptool-args.def
 src/Makefile
 src/Makefile.in
 src/benchmark
@@ -549,8 +551,10 @@ doc/reference/*.bak
 doc/manpages/gnutls_*.3
 doc/examples/ex-ocsp-client
 doc/examples/ex-ocsp-verify
+doc/manpages/gnutls-cli.1
 doc/examples/ex-client-anon
 doc/examples/ex-client-dtls
 doc/examples/ex-client-x509
 doc/examples/ex-serv-x509
 tests/slow/cipher-test
+libopts/libopts.la
index 7af15575681746b0e1dea0265bb74556bb12b423..d63830d82a920ce60da848885354cbdf16add583 100644 (file)
 
 DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --disable-valgrind-tests
 
-SUBDIRS = gl lib extra po src doc tests
+SUBDIRS = gl lib extra po 
+
+if NEED_LIBOPTS
+SUBDIRS += libopts
+endif
+
+SUBDIRS += src doc tests
 
 if HAVE_GUILE
 SUBDIRS += guile
index eecaec7e3eb94438d3825474ba0c11737bd84af6..8775a93e475e0abd93076596951c98dc71a5a0ca 100644 (file)
@@ -123,8 +123,6 @@ AC_C_BIGENDIAN
 
 
 
-dnl Checks for functions
-
 dnl No fork on MinGW, disable some self-tests until we fix them.
 AC_CHECK_FUNCS(fork,,)
 AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no")
@@ -156,6 +154,9 @@ fi
 
 AM_CONDITIONAL(ENABLE_PKCS11, test "$with_p11_kit" != "no")
 
+dnl Checks for programs in src/ 
+LIBOPTS_CHECK([libopts])
+
 dnl Check for libcfg+
 SAVED_LIBS=$LIBS
 AC_ARG_WITH(included-libcfg,
@@ -285,6 +286,7 @@ if test "$gl_gcc_warnings" = yes; then
   gl_WARN_ADD([-Wno-unused-parameter]) # Too many warnings for now
   gl_WARN_ADD([-Wno-stack-protector])  # Some functions cannot be protected
   gl_WARN_ADD([-Wno-int-to-pointer-cast])  # Some files cannot be compiled with that (gl_fd_to_handle)
+  gl_WARN_ADD([-Wno-redundant-decls])  # Some files cannot be compiled with that (gl_fd_to_handle)
   gl_WARN_ADD([-fdiagnostics-show-option])
 fi
 
@@ -485,6 +487,9 @@ AC_CONFIG_FILES([
   lib/x509/Makefile
   po/Makefile.in
   src/Makefile
+  src/cli-args.def
+  src/cli-debug-args.def
+  src/srptool-args.def
   src/cfg/Makefile
   src/cfg/platon/Makefile
   src/cfg/platon/str/Makefile
index 5057a076dae8e9a71a3604bef59062673a5049f6..6ddcea6524c7fe417e219fe3659564d2c4ac5e45 100644 (file)
@@ -26,6 +26,15 @@ if ENABLE_SRP
 dist_man_MANS += srptool.1
 endif
 
+gnutls-cli.1: ../../src/cli-args.def
+       -autogen -DMAN_SECTION=1 -Tagman-cmd.tpl $<
+
+gnutls-cli-debug.1: ../../src/cli-debug-args.def
+       -autogen -DMAN_SECTION=1 -Tagman-cmd.tpl $<
+
+srptool.1: ../../src/srptool-args.def
+       -autogen -DMAN_SECTION=1 -Tagman-cmd.tpl $<
+
 APIMANS =
 APIMANS += gnutls_pubkey_init.3
 APIMANS += gnutls_pubkey_deinit.3
diff --git a/doc/manpages/gnutls-cli.1 b/doc/manpages/gnutls-cli.1
deleted file mode 100644 (file)
index 8a42a5c..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-.TH gnutls\-cli 1 "December 1st 2003"
-.SH NAME
-gnutls\-cli \- GnuTLS test client
-.SH SYNOPSIS
-gnutls\-cli [\fIoptions\fR] \fIhostname\fI
-.SH DESCRIPTION
-Simple client program to set up a TLS connection to some other
-computer.  It sets up a TLS connection and forwards data from the
-standard input to the secured socket and vice versa.
-.SH OPTIONS
-.SS Program control options
-.IP "\-d, \-\-debug LEVEL"
-Specify the debug level. Default is 1.
-.IP "\-h, \-\-help"
-Prints a short reminder of the command line options.
-.IP "\-l, \-\-list"
-Print a list of the supported algorithms and modes.
-.IP "\-r, \-\-resume"
-Connect, establish a session.  Connect again and resume this session.
-.IP "\-s, \-\-starttls"
-Connect, establish a plain session and start TLS when EOF or a SIGALRM
-is received.
-.IP "\-v, \-\-version"
-Prints the program's version number.
-.IP "\-V, \-\-verbose"
-More verbose output.
-
-.SS TLS/SSL control options
-.IP "\-\-priority \fIPRIORITY STRING\fR"
-TLS algorithms and protocols to enable.
-You can use predefined sets of ciphersuites such as: 
-.IP
-.B "PERFORMANCE"
-all the "secure" ciphersuites are enabled, limited to 128 bit
-ciphers and sorted by terms of speed performance.
-.IP 
-.B "NORMAL" 
-option enables all "secure" ciphersuites. The 256-bit ciphers
-are included as a fallback only. The ciphers are sorted by security
-margin.
-.IP 
-.B "SECURE128" 
-flag enables all "secure" ciphersuites with ciphers up to
-128 bits, sorted by security margin.
-.IP 
-.B "SECURE256" 
-flag enables all "secure" ciphersuites including the 256 bit
-ciphers, sorted by security margin.
-.IP 
-.B "EXPORT" 
-all the ciphersuites are enabled, including the
-low-security 40 bit ciphers.
-.IP 
-.B "NONE" 
-nothing is enabled. This disables even protocols and
-compression methods.
-.IP
-.IP
-Check the GnuTLS manual on section "Priority strings" for
-more information on allowed keywords.
-.IP 
-.B Examples:
-.IP 
-"NORMAL"
-.IP 
-"NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"
-.IP 
-"NORMAL:-ARCFOUR-128" means normal ciphers except for ARCFOUR-128.
-.IP 
-"SECURE:-VERS-SSL3.0:+COMP-DEFLATE" means that only secure ciphers are
-enabled, SSL3.0 is disabled, and libz compression enabled.
-.IP
- "NONE:+VERS-TLS-ALL:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1"
-.IP 
-"NORMAL:%COMPAT" is the most compatible mode
-
-.IP "\-\-crlf"
-Send CR LF instead of LF.
-.IP "\-f, \-\-fingerprint"
-Send the openpgp fingerprint, instead of the key.
-.IP "\-p, \-\-port \fIinteger\fR"
-The port to connect to.
-.IP "\-\-ciphers \fIcipher1 cipher2...\fR"
-Ciphers to enable (use \fBgnutls\-cli \-\-list\fR to show the
-supported ciphers).
-.IP "\-\-protocols \fIprotocol1 protocol2...\fR"
-Protocols to enable (use \fBgnutls\-cli \-\-list\fR to show the
-supported protocols).
-.IP "\-\-comp \fIcomp1 comp2...\fR"
-Compression methods to enable (use \fBgnutls\-cli \-\-list\fR to
-show the supported methods).
-.IP "\-\-macs \fImac1 mac2...\fR"
-MACs to enable (use \fBgnutls\-cli \-\-list\fR to show the
-supported MACs).
-.IP "\-\-kx \fIkx1 kx2...\fR"
-Key exchange methods to enable (use \fBgnutls\-cli \-\-list\fR to
-show the supported methods).
-.IP "\-\-ctypes \fIcertType1 certType2...\fR"
-Certificate types to enable (use \fBgnutls\-cli \-\-list\fR to show
-the supported types).
-.IP "\-\-recordsize \fIinteger\fR"
-The maximum record size to advertize.
-.IP "\-\-disable-extensions"
-Disable all the TLS extensions.
-.IP "\-\-print-cert"
-Print the certificate in PEM format.
-.IP "\-\-insecure"
-Don't abort program if server certificates can't be validated.
-
-.SS Certificate options
-.IP "\-\-pgpcertfile \fIFILE\fR"
-PGP Public Key (certificate) file to use.
-.IP "\-\-pgpkeyfile \fIFILE\fR"
-PGP Key file to use.
-.IP "\-\-pgpkeyring \fIFILE\fR"
-PGP Key ring file to use.
-.IP "\-\-pgptrustdb \fIFILE\fR"
-PGP trustdb file to use.
-.IP "\-\-pgpsubkey \fIHEX|auto\fR2
-PGP subkey to use.
-.IP "\-\-srppasswd \fIPASSWD\fR"
-SRP password to use.
-.IP "\-\-srpusername \fINAME\fR"
-SRP username to use.
-.IP "\-\-x509cafile \fIFILE\fR"
-Certificate file to use. This option accepts PKCS #11 URLs such as
-"pkcs11:token=xxx"
-.IP "\-\-x509certfile \fIFILE\fR"
-X.509 Certificate file to use, or a PKCS #11 URL.
-.IP "\-\-x509fmtder"
-Use DER format for certificates
-.IP "\-\-x509keyfile \fIFILE\fR"
-X.509 key file or PKCS #11 URL to use.
-.IP "\-\-x509crlfile \fIFILE\fR"
-X.509 CRL file to use.
-.IP "\-\-pskusername \fINAME\fR"
-PSK username to use.
-.IP "\-\-pskkey \fIKEY\fR"
-PSK key (in hex) to use.
-.IP "\-\-opaque-prf-input \fIDATA\fR"
-Use Opaque PRF Input DATA.
-
-.SH "SEE ALSO"
-.BR gnutls\-cli\-debug (1),
-.BR gnutls\-serv (1)
-.SH AUTHOR
-.PP
-Nikos Mavrogiannopoulos <nmav@gnutls.org> and others; see
-/usr/share/doc/gnutls\-bin/AUTHORS for a complete list.
-.PP
-This manual page was written by Ivo Timmermans <ivo@debian.org>, for
-the Debian GNU/Linux system (but may be used by others).
index 0904b6f218e5a5ff050a75e147241c96ca80b7e0..0933107868ee62908a9b6753b0d9fd9e35b62381 100644 (file)
-.TH srptool 1 "February 21st 2005"
+.TH srptool 1 "18 Jan 2012" "3.0.11" "User Commands"
+.\"
+.\"  DO NOT EDIT THIS FILE   (srptool-args.man)
+.\"  
+.\"  It has been AutoGen-ed  January 18, 2012 at 11:34:29 PM by AutoGen 5.12
+.\"  From the definitions    ../../src/srptool-args.def
+.\"  and the template file   agman-cmd.tpl
+.\"
 .SH NAME
-srptool \- Simple SRP password tool
+srptool \- GnuTLS SRP tool
 .SH SYNOPSIS
-srptool [\fIoptions\fR]
-.SH DESCRIPTION
-Very simple program that emulates the programs in the Stanford SRP
-(Secure Remote Password) libraries using GnuTLS.
-It is intended for use in places where you don't expect SRP
-authentication to be the used for system users.
-
-In brief, to use SRP you need to create two files. These are 
-the password file that holds the users and the verifiers associated with them
-and the configuration file to hold the group parameters 
-(called tpasswd.conf).
-.SH OPTIONS
-.IP "\-\-bits \fIBITS\fR"
-specify the number of bits for prime numbers (used only when the
-\fB\-\-create\-conf\fR option is used).
-.IP "\-\-create\-conf \fIFILE\fR"
-Generate a tpasswd.conf file.
-.IP "\-h, \-\-help"
-Prints a short reminder of the command line options.
-.IP "\-i, \-\-index \fIINDEX\fR"
-Specify the index of the parameters in tpasswd.conf to use.
-.IP "\-p, \-\-passwd \fIFILE\fR"
-Specify a password file.
-.IP "\-c, \-\-passwd\-conf \fIFILE\fR"
-Specify a password configuration file.
-.IP "\-s, \-\-salt \fISALT\fR"
-Specify salt size for crypt algorithm.
-.IP "\-u, \-\-username \fIusername\fR"
-Specify username.
-.IP "\-\-verify"
-Just verify password.
+.B srptool
+.\" Mixture of short (flag) options and long options
+.RB [ \-\fIflag\fP " [\fIvalue\fP]]... [" \-\-\fIopt\-name\fP " [[=| ]\fIvalue\fP]]..." 
+.PP
+Operands and options may be intermixed.  They will be reordered.
+.SH "DESCRIPTION"
+Simple program that emulates the programs in the Stanford SRP (Secure
+Remote Password) libraries using GnuTLS.  It is intended for use in  places
+where you don't expect SRP authentication to be the used for system users.
+In  brief,  to use SRP you need to create two files. These are the password
+file that holds the users and the verifiers associated with  them  and  the
+configuration file to hold the group parameters (called tpasswd.conf).
+.SH "OPTIONS"
+.TP
+.BR \-d " \fInumber\fP, " \-\-debug "=" \fInumber\fP
+Enable debugging..
+This option takes an integer number as its argument.
+The value of \fInumber\fP is constrained to being:
+.in +4
+.nf
+.na
+in the range  0 through 9999
+.fi
+.in -4
+.sp
+Specifies the debug level.
+.TP
+.BR \-i ", " -\-index
+specify the index of the group parameters in tpasswd.conf to use..
+.sp
+.TP
+.BR \-u " \fIstring\fP, " \-\-username "=" \fIstring\fP
+specify a username.
+.sp
+.TP
+.BR \-p " \fIstring\fP, " \-\-passwd "=" \fIstring\fP
+specify a password file..
+.sp
+.TP
+.BR \-s " \fInumber\fP, " \-\-salt "=" \fInumber\fP
+specify salt size for crypt algorithm..
+This option takes an integer number as its argument.
+.sp
+.TP
+.BR \-\-verify
+just verify the password..
+.sp
+Verifies the password provided against the password file.
+.TP
+.BR \-v " \fIfile\fP, " \-\-passwd\-conf "=" \fIfile\fP
+specify a password conf file..
+.sp
+Specify a filename or a PKCS #11 URL to read the CAs from.
+.TP
+.BR \-\-create\-conf "=\fIfile\fP"
+Generate a password configuration file..
+.sp
+This generates a password configuration file (tpasswd.conf)
+containing the required for TLS parameters.
+.TP
+.BR \-? , " \-\-help"
+Display usage information and exit.
+.TP
+.BR \-! , " \-\-more-help"
+Pass the extended usage information through a pager.
+.TP
+.BR \-v " [{\fIv|c|n\fP}]," " \-\-version" "[=\fI{v|c|n}\fP]"
+Output version of program and exit.  The default mode is `v', a simple
+version.  The `c' mode will print copyright information and `n' will
+print the full copyright notice.
 .SH EXAMPLES
-To create tpasswd.conf which holds the g and n values for SRP protocol
+To create \fItpasswd.conf\fP which holds the g and n values for SRP protocol
 (generator and a large prime), run:
-
-.RS
+.br
+.in +4
 .nf
 $ srptool \-\-create\-conf /etc/tpasswd.conf
+.in -4
 .fi
-.RE
-
-This command will create /etc/tpasswd and will add user 'test' (you
+.sp
+This command will create \fI/etc/tpasswd\fP and will add user 'test' (you
 will also be prompted for a password). Verifiers are stored by default
 in the way libsrp expects.
-
-.RS
+.br
+.in +4
 .nf
-$ srptool \-\-passwd /etc/tpasswd \\
-    \-\-passwd\-conf /etc/tpasswd.conf \-u test
+srptool \-\-passwd /etc/tpasswd \-\-passwd\-conf /etc/tpasswd.conf \-u test
+.in -4
 .fi
-.RE
-
+.sp
+.sp
 This command will check against a password. If the password matches
-the one in /etc/tpasswd you will get an ok.
-
-.RS
+the one in \fI/etc/tpasswd\fP you will get an ok.
+.br
+.in +4
 .nf
-$ srptool \-\-passwd /etc/tpasswd \\
-    \-\-passwd\-conf /etc/tpasswd.conf \-\-verify \-u test
+$ srptool \-\-passwd /etc/tpasswd \-\-passwd\-conf /etc/tpasswd.conf \-\-verify \-u test
+.in -4
 .fi
-.RE
-
-.SH AUTHOR
-.PP
-Nikos Mavrogiannopoulos <nmav@gnutls.org> and others; see
-/usr/share/doc/gnutls\-bin/AUTHORS for a complete list.
-.PP
-This manual page was written by Ivo Timmermans <ivo@debian.org>, for
-the Debian GNU/Linux system (but may be used by others).
+.SH "EXIT STATUS"
+One of the following exit values will be returned:
+.TP
+.BR 0
+Successful program execution.
+.TP
+.BR 1
+The operation failed or the command syntax was not valid.
+.SH "SEE ALSO"
+    gnutls-cli-debug (1), gnutls-serv (1), srptool (1), psktool (1), certtool (1)
+.SH "AUTHORS"
+Nikos Mavrogiannopoulos and Simon Josefsson
+.SH "COPYRIGHT"
+Copyright (C) 2000-2012 Free Software Foundation all rights reserved.
+This program is released under the terms of the GNU General Public License, version 3 or later.
+.SH "BUGS"
+Please send bug reports to: bug-gnutls@gnu.org
+.SH "NOTES"
+This manual page was \fIAutoGen\fP-erated from the \fBsrptool\fP
+option definitions.
diff --git a/libopts/COPYING.gplv3 b/libopts/COPYING.gplv3
new file mode 100644 (file)
index 0000000..6c1b848
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    copyright (c) by Bruce Korb - all rights reserved
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  copyright (c)  by Bruce Korb - all rights reserved
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/libopts/COPYING.lgplv3 b/libopts/COPYING.lgplv3
new file mode 100644 (file)
index 0000000..c7759a0
--- /dev/null
@@ -0,0 +1,165 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/libopts/COPYING.mbsd b/libopts/COPYING.mbsd
new file mode 100644 (file)
index 0000000..8a70427
--- /dev/null
@@ -0,0 +1,26 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+
+    2. 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.
+
+    3. The name of the author may not be used to endorse or promote
+       products derived from this software without specific prior
+       written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
diff --git a/libopts/MakeDefs.inc b/libopts/MakeDefs.inc
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/libopts/Makefile.am b/libopts/Makefile.am
new file mode 100644 (file)
index 0000000..4b33941
--- /dev/null
@@ -0,0 +1,29 @@
+## LIBOPTS Makefile
+MAINTAINERCLEANFILES    = Makefile.in
+if INSTALL_LIBOPTS
+lib_LTLIBRARIES         = libopts.la
+else
+noinst_LTLIBRARIES      = libopts.la
+endif
+libopts_la_SOURCES      = libopts.c
+libopts_la_CPPFLAGS     = -I$(top_srcdir)
+libopts_la_LDFLAGS      = -version-info  36:1:11
+EXTRA_DIST              = \
+    ag-char-map.h           autoopts/usage-txt.h    autoopts/options.h  \
+    autoopts/project.h      autoopts.c              autoopts.h  \
+    boolean.c               check.c                 compat/strchr.c  \
+    compat/strdup.c         compat/snprintf.c       compat/pathfind.c  \
+    compat/compat.h         compat/windows-config.h configfile.c  \
+    cook.c                  COPYING.gplv3           COPYING.lgplv3  \
+    COPYING.mbsd            enum.c                  env.c  \
+    file.c                  find.c                  genshell.c  \
+    genshell.h              load.c                  m4/libopts.m4  \
+    m4/liboptschk.m4        MakeDefs.inc            makeshell.c  \
+    nested.c                numeric.c               parse-duration.c  \
+    parse-duration.h        pgusage.c               proto.h  \
+    putshell.c              README                  reset.c  \
+    restore.c               save.c                  sort.c  \
+    stack.c                 streqvcmp.c             text_mmap.c  \
+    time.c                  tokenize.c              usage.c  \
+    value-type.c            value-type.h            version.c  \
+    xat-attribute.c         xat-attribute.h
diff --git a/libopts/README b/libopts/README
new file mode 100644 (file)
index 0000000..afa5409
--- /dev/null
@@ -0,0 +1,122 @@
+        THIS TARBALL IS NOT A FULL DISTRIBUTION.
+
+The contents of this tarball is designed to be incorporated into
+software packages that utilize the AutoOpts option automation package
+and are intended to be installed on systems that may not have libopts
+installed.  It is redistributable under the terms of either the LGPL
+(see COPYING.lgpl) or under the terms of the advertising clause free BSD
+license (see COPYING.mbsd).
+
+Usage Instructions for autoconf/automake/libtoolized projects:
+
+1. Install the unrolled tarball into your package source tree,
+   copying ``libopts.m4'' to your autoconf macro directory.
+
+   In your bootstrap (pre-configure) script, you can do this:
+
+      rm -rf libopts libopts-*
+      gunzip -c `autoopts-config libsrc` | tar -xvf -
+      mv -f libopts-*.*.* libopts
+      cp -fp libopts/m4/*.m4 m4/.
+
+   I tend to put my configure auxiliary files in "m4".
+   Whatever directory you choose, if it is not ".", then
+   be sure to tell autoconf about it with:
+
+      AC_CONFIG_AUX_DIR(m4)
+
+   This is one macro where you *MUST* remember to *NOT* quote
+   the argument.  If you do, automake will get lost.
+
+2. Add an invocation of either LIBOPTS_CHECK or LIBOPTS_CHECK_NOBUILD
+   to your configure.ac file.  See LIBOPTS_CHECK: below for details.
+
+3. Add the following to your top level ``Makefile.am'' file:
+
+      if NEED_LIBOPTS
+         SUBDIRS += $(LIBOPTS_DIR)
+      endif
+
+   where ``<...>'' can be whatever other files or directories you may
+   need.  The SUBDIRS must be properly ordered.  *PLEASE NOTE* it is
+   crucial that the SUBDIRS be set under the control of an automake
+   conditional.  To work correctly, automake has to know the range of
+   possible values of SUBDIRS.  It's a magical name with magical
+   properties.  ``NEED_LIBOPTS'' will be correctly set by the
+   ``LIBOPTS_CHECK'' macro, above.
+
+4. Add ``$(LIBOPTS_CFLAGS)'' to relevant compiler flags and
+   ``$(LIBOPTS_LDADD)'' to relevant link options whereever
+   you need them in your build tree.
+
+5. Make sure your object files explicitly depend upon the
+   generated options header file.  e.g.:
+
+     $(prog_OBJECTS) : prog-opts.h
+     prog-opts.h : prog-opts.c
+     prog-opts.c : prog-opts.def
+         autogen prog-opts.def
+
+6. *OPTIONAL* --
+   If you are creating man pages and texi documentation from
+   the program options, you will need these rules somewhere, too:
+
+     man_MANS = prog.1
+     prog.1 : prog-opts.def
+         autogen -Tagman-cmd.tpl -bprog prog-opts.def
+
+     invoke-prog.texi : prog-opts.def
+         autogen -Tagtexi-cmd.tpl prog-opts.def
+
+If your package does not utilize the auto* tools, then you
+will need to hand craft the rules for building the library.
+
+LIBOPTS_CHECK:
+
+The arguments to both macro are a relative path to the directory with
+the libopts source code.  It is optional and defaults to "libopts".
+These macros work as follows:
+
+1.  LIBOPTS_CHECK([libopts/rel/path/optional])
+
+    Adds two command-line options to the generated configure script,
+    --enable-local-libopts and --disable-libopts-install.  AC_SUBST's
+    LIBOPTS_CFLAGS, LIBOPTS_LDADD, and LIBOPTS_DIR for use in
+    Makefile.am files.  Adds Automake conditional NEED_LIBOPTS which
+    will be true when the local copy of libopts should be built.  Uses
+    AC_CONFIG_FILES([$libopts-dir/Makefile]) to cause the local libopts
+    into the package build.  If the optional relative path to libopts is
+    not provided, it defaults to simply "libopts".
+
+2.  LIBOPTS_CHECK_NOBUILD([libopts/rel/path/optional])
+
+    This variant of LIBOPTS_CHECK is useful when multiple configure.ac
+    files in a package make use of a single libopts tearoff.  In that
+    case, only one of the configure.ac files should build libopts and
+    others should simply use it.  Consider this package arrangment:
+
+    all-tools/
+      configure.ac
+      common-tools/
+        configure.ac
+        libopts/
+
+    The parent package all-tools contains a subpackage common-tools
+    which can be torn off and used independently.  Programs configured
+    by both configure.ac files link against the common-tools/libopts
+    tearoff, when not using the system's libopts.  The top-level
+    configure.ac uses LIBOPTS_CHECK_NOBUILD([common-tools/libopts]),
+    while common-tools/configure.ac uses LIBOPTS_CHECK.  The difference
+    is LIBOPTS_CHECK_NOBUILD will never build the libopts tearoff,
+    leaving that to the subpackage configure.ac's LIBOPTS_CHECK.
+    Specifically, LIBOPTS_CHECK_NOBUILD always results in the
+    NEED_LIBOPTS Automake conditional being false, and does not invoke
+    AC_CONFIG_FILES(path-to-libopts/Makefile).
+
+LICENSING:
+
+This material is Copyright (c) 1992-2011 by Bruce Korb.  You are
+licensed to use this under the terms of either the GNU Lesser General
+Public License (see: COPYING.lgpl), or, at your option, the modified
+Berkeley Software Distribution License (see: COPYING.mbsd).  Both of
+these files should be included with this tarball.
diff --git a/libopts/ag-char-map.h b/libopts/ag-char-map.h
new file mode 100644 (file)
index 0000000..0fb9794
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *   Character mapping generated 12/29/11 12:02:33
+ *
+ *  This file contains the character classifications
+ *  used by AutoGen and AutoOpts for identifying tokens.
+ *  This file is part of AutoGen.
+ *  Copyright (c) 1992-2011 Bruce Korb - all rights reserved
+ *  AutoGen is free software: you can redistribute it and/or modify it under the
+ *  terms of the GNU General Public License as published by the Free Software
+ *  Foundation, either version 3 of the License, or (at your option) any later
+ *  version.
+ *  AutoGen is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ *  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef AG_CHAR_MAP_H_GUARD
+#define AG_CHAR_MAP_H_GUARD 1
+
+#ifdef HAVE_CONFIG_H
+# if defined(HAVE_INTTYPES_H)
+#  include <inttypes.h>
+# elif defined(HAVE_STDINT_H)
+#  include <stdint.h>
+
+# else
+#   ifndef HAVE_INT8_T
+        typedef signed char     int8_t;
+#   endif
+#   ifndef HAVE_UINT8_T
+        typedef unsigned char   uint8_t;
+#   endif
+#   ifndef HAVE_INT16_T
+        typedef signed short    int16_t;
+#   endif
+#   ifndef HAVE_UINT16_T
+        typedef unsigned short  uint16_t;
+#   endif
+#   ifndef HAVE_UINT_T
+        typedef unsigned int    uint_t;
+#   endif
+
+#   ifndef HAVE_INT32_T
+#    if SIZEOF_INT == 4
+        typedef signed int      int32_t;
+#    elif SIZEOF_LONG == 4
+        typedef signed long     int32_t;
+#    endif
+#   endif
+
+#   ifndef HAVE_UINT32_T
+#    if SIZEOF_INT == 4
+        typedef unsigned int    uint32_t;
+#    elif SIZEOF_LONG == 4
+        typedef unsigned long   uint32_t;
+#    endif
+#   endif
+# endif /* HAVE_*INT*_H header */
+
+#else /* not HAVE_CONFIG_H -- */
+# ifdef __sun
+#  include <inttypes.h>
+# else
+#  include <stdint.h>
+# endif
+#endif /* HAVE_CONFIG_H */
+
+#if 0 /* mapping specification source (from autogen.map) */
+// 
+// %guard          autoopts_internal
+// %file           ag-char-map.h
+// %static-table   option-char-category
+// 
+// %comment
+//   This file contains the character classifications
+//   used by AutoGen and AutoOpts for identifying tokens.
+// 
+//   This file is part of AutoGen.
+//   Copyright (c) 1992-2011 Bruce Korb - all rights reserved
+// 
+//   AutoGen is free software: you can redistribute it and/or modify it under the
+//   terms of the GNU General Public License as published by the Free Software
+//   Foundation, either version 3 of the License, or (at your option) any later
+//   version.
+// 
+//   AutoGen is distributed in the hope that it will be useful, but WITHOUT ANY
+//   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+//   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+// 
+//   You should have received a copy of the GNU General Public License along
+//   with this program.  If not, see <http://www.gnu.org/licenses/>.
+// %
+// 
+// lower-case      "a-z"
+// upper-case      "A-Z"
+// alphabetic      +lower-case   +upper-case
+// oct-digit       "0-7"
+// dec-digit       "89"          +oct-digit
+// hex-digit       "a-fA-F"      +dec-digit
+// alphanumeric    +alphabetic   +dec-digit
+// var-first       "_"           +alphabetic
+// variable-name   +var-first    +dec-digit
+// option-name     "^-"          +variable-name
+// value-name      ":"           +option-name
+// horiz-white     "\t "
+// compound-name   "[.]"         +value-name   +horiz-white
+// whitespace      "\v\f\r\n\b"  +horiz-white
+// unquotable      "!-~"         -"\"#(),;<=>[\\]`{}?*'"
+// end-xml-token   "/>"          +whitespace
+// graphic         "!-~"
+// plus-n-space    "+"           +whitespace
+// punctuation     "!-~"         -alphanumeric -"_"
+// suffix          "-._"         +alphanumeric
+// suffix-fmt      "%/"          +suffix     
+// false-type      "nNfF0\x00"
+// file-name       "/"           +suffix
+// end-token       "\x00"        +whitespace
+// end-list-entry  ","           +end-token
+//
+#endif /* 0 -- mapping spec. source */
+
+typedef uint32_t option_char_category_mask_t;
+static option_char_category_mask_t const option_char_category[128];
+
+static inline int is_option_char_category_char(char ch, option_char_category_mask_t mask) {
+    unsigned int ix = (unsigned char)ch;
+    return ((ix < 128) && ((option_char_category[ix] & mask) != 0)); }
+
+#define IS_LOWER_CASE_CHAR(_c)      is_option_char_category_char((_c), 0x000001)
+#define IS_UPPER_CASE_CHAR(_c)      is_option_char_category_char((_c), 0x000002)
+#define IS_ALPHABETIC_CHAR(_c)      is_option_char_category_char((_c), 0x000003)
+#define IS_OCT_DIGIT_CHAR(_c)       is_option_char_category_char((_c), 0x000004)
+#define IS_DEC_DIGIT_CHAR(_c)       is_option_char_category_char((_c), 0x00000C)
+#define IS_HEX_DIGIT_CHAR(_c)       is_option_char_category_char((_c), 0x00001C)
+#define IS_ALPHANUMERIC_CHAR(_c)    is_option_char_category_char((_c), 0x00000F)
+#define IS_VAR_FIRST_CHAR(_c)       is_option_char_category_char((_c), 0x000023)
+#define IS_VARIABLE_NAME_CHAR(_c)   is_option_char_category_char((_c), 0x00002F)
+#define IS_OPTION_NAME_CHAR(_c)     is_option_char_category_char((_c), 0x00006F)
+#define IS_VALUE_NAME_CHAR(_c)      is_option_char_category_char((_c), 0x0000EF)
+#define IS_HORIZ_WHITE_CHAR(_c)     is_option_char_category_char((_c), 0x000100)
+#define IS_COMPOUND_NAME_CHAR(_c)   is_option_char_category_char((_c), 0x0003EF)
+#define IS_WHITESPACE_CHAR(_c)      is_option_char_category_char((_c), 0x000500)
+#define IS_UNQUOTABLE_CHAR(_c)      is_option_char_category_char((_c), 0x000800)
+#define IS_END_XML_TOKEN_CHAR(_c)   is_option_char_category_char((_c), 0x001500)
+#define IS_GRAPHIC_CHAR(_c)         is_option_char_category_char((_c), 0x002000)
+#define IS_PLUS_N_SPACE_CHAR(_c)    is_option_char_category_char((_c), 0x004500)
+#define IS_PUNCTUATION_CHAR(_c)     is_option_char_category_char((_c), 0x008000)
+#define IS_SUFFIX_CHAR(_c)          is_option_char_category_char((_c), 0x01000F)
+#define IS_SUFFIX_FMT_CHAR(_c)      is_option_char_category_char((_c), 0x03000F)
+#define IS_FALSE_TYPE_CHAR(_c)      is_option_char_category_char((_c), 0x040000)
+#define IS_FILE_NAME_CHAR(_c)       is_option_char_category_char((_c), 0x09000F)
+#define IS_END_TOKEN_CHAR(_c)       is_option_char_category_char((_c), 0x100500)
+#define IS_END_LIST_ENTRY_CHAR(_c)  is_option_char_category_char((_c), 0x300500)
+
+#if 1 /* def AUTOOPTS_INTERNAL */
+static option_char_category_mask_t const option_char_category[128] = {
+  /*x00*/ 0x140000, /*x01*/ 0x000000, /*x02*/ 0x000000, /*x03*/ 0x000000,
+  /*x04*/ 0x000000, /*x05*/ 0x000000, /*x06*/ 0x000000, /*\a */ 0x000000,
+  /*\b */ 0x000400, /*\t */ 0x000100, /*\n */ 0x000400, /*\v */ 0x000400,
+  /*\f */ 0x000400, /*\r */ 0x000400, /*x0E*/ 0x000000, /*x0F*/ 0x000000,
+  /*x10*/ 0x000000, /*x11*/ 0x000000, /*x12*/ 0x000000, /*x13*/ 0x000000,
+  /*x14*/ 0x000000, /*x15*/ 0x000000, /*x16*/ 0x000000, /*x17*/ 0x000000,
+  /*x18*/ 0x000000, /*x19*/ 0x000000, /*x1A*/ 0x000000, /*x1B*/ 0x000000,
+  /*x1C*/ 0x000000, /*x1D*/ 0x000000, /*x1E*/ 0x000000, /*x1F*/ 0x000000,
+  /*   */ 0x000100, /* ! */ 0x00A800, /* " */ 0x00A000, /* # */ 0x00A000,
+  /* $ */ 0x00A800, /* % */ 0x02A800, /* & */ 0x00A800, /* ' */ 0x00A000,
+  /* ( */ 0x00A000, /* ) */ 0x00A000, /* * */ 0x00A000, /* + */ 0x00E800,
+  /* , */ 0x20A000, /* - */ 0x01A840, /* . */ 0x01AA00, /* / */ 0x0AB800,
+  /* 0 */ 0x042804, /* 1 */ 0x002804, /* 2 */ 0x002804, /* 3 */ 0x002804,
+  /* 4 */ 0x002804, /* 5 */ 0x002804, /* 6 */ 0x002804, /* 7 */ 0x002804,
+  /* 8 */ 0x002808, /* 9 */ 0x002808, /* : */ 0x00A880, /* ; */ 0x00A000,
+  /* < */ 0x00A000, /* = */ 0x00A000, /* > */ 0x00B000, /* ? */ 0x00A000,
+  /* @ */ 0x00A800, /* A */ 0x002812, /* B */ 0x002812, /* C */ 0x002812,
+  /* D */ 0x002812, /* E */ 0x002812, /* F */ 0x042812, /* G */ 0x002802,
+  /* H */ 0x002802, /* I */ 0x002802, /* J */ 0x002802, /* K */ 0x002802,
+  /* L */ 0x002802, /* M */ 0x002802, /* N */ 0x042802, /* O */ 0x002802,
+  /* P */ 0x002802, /* Q */ 0x002802, /* R */ 0x002802, /* S */ 0x002802,
+  /* T */ 0x002802, /* U */ 0x002802, /* V */ 0x002802, /* W */ 0x002802,
+  /* X */ 0x002802, /* Y */ 0x002802, /* Z */ 0x002802, /* [ */ 0x00A200,
+  /* \ */ 0x00A000, /* ] */ 0x00A200, /* ^ */ 0x00A840, /* _ */ 0x012820,
+  /* ` */ 0x00A000, /* a */ 0x002811, /* b */ 0x002811, /* c */ 0x002811,
+  /* d */ 0x002811, /* e */ 0x002811, /* f */ 0x042811, /* g */ 0x002801,
+  /* h */ 0x002801, /* i */ 0x002801, /* j */ 0x002801, /* k */ 0x002801,
+  /* l */ 0x002801, /* m */ 0x002801, /* n */ 0x042801, /* o */ 0x002801,
+  /* p */ 0x002801, /* q */ 0x002801, /* r */ 0x002801, /* s */ 0x002801,
+  /* t */ 0x002801, /* u */ 0x002801, /* v */ 0x002801, /* w */ 0x002801,
+  /* x */ 0x002801, /* y */ 0x002801, /* z */ 0x002801, /* { */ 0x00A000,
+  /* | */ 0x00A800, /* } */ 0x00A000, /* ~ */ 0x00A800, /*x7F*/ 0x000000
+};
+#endif /* AUTOOPTS_INTERNAL */
+#endif /* AG_CHAR_MAP_H_GUARD */
diff --git a/libopts/autoopts.c b/libopts/autoopts.c
new file mode 100644 (file)
index 0000000..c1129f2
--- /dev/null
@@ -0,0 +1,720 @@
+
+/**
+ * \file autoopts.c
+ *
+ *  Time-stamp:      "2011-08-07 14:31:49 bkorb"
+ *
+ *  This file contains all of the routines that must be linked into
+ *  an executable to use the generated option processing.  The optional
+ *  routines are in separately compiled modules so that they will not
+ *  necessarily be linked in.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+#ifndef PKGDATADIR
+#  define PKGDATADIR ""
+#endif
+
+static char const   zNil[] = "";
+static arg_types_t  argTypes             = { NULL };
+static char         zOptFmtLine[32]      = { NUL };
+static ag_bool      displayEnum          = AG_FALSE;
+static char const   pkgdatadir_default[] = PKGDATADIR;
+static char const * program_pkgdatadir   = pkgdatadir_default;
+static tOptionLoadMode option_load_mode  = OPTION_LOAD_UNCOOKED;
+static tePagerState pagerState           = PAGER_STATE_INITIAL;
+
+       FILE *       option_usage_fp      = NULL;
+
+/* = = = START-STATIC-FORWARD = = = */
+static tSuccess
+next_opt_arg_must(tOptions * pOpts, tOptState* pOptState);
+
+static tSuccess
+next_opt_arg_may(tOptions * pOpts, tOptState* pOptState);
+
+static tSuccess
+next_opt_arg_none(tOptions * pOpts, tOptState* pOptState);
+
+static tSuccess
+next_opt(tOptions * pOpts, tOptState * pOptState);
+
+static tSuccess
+doPresets(tOptions * pOpts);
+/* = = = END-STATIC-FORWARD = = = */
+
+LOCAL void *
+ao_malloc(size_t sz)
+{
+    void * res = malloc(sz);
+    if (res == NULL) {
+        fprintf(stderr, zAO_Alloc, (int)sz);
+        exit(EXIT_FAILURE);
+    }
+    return res;
+}
+#undef  malloc
+#define malloc(_s) ao_malloc(_s)
+
+LOCAL void *
+ao_realloc(void *p, size_t sz)
+{
+    void * res = (p == NULL) ? malloc(sz) : realloc(p, sz);
+    if (res == NULL) {
+        fprintf(stderr, zAO_Realloc, (int)sz, p);
+        exit(EXIT_FAILURE);
+    }
+    return res;
+}
+#undef  realloc
+#define realloc(_p,_s) ao_realloc(_p,_s)
+
+LOCAL char *
+ao_strdup(char const *str)
+{
+    char * res = strdup(str);
+    if (res == NULL) {
+        fprintf(stderr, zAO_Strdup, (int)strlen(str));
+        exit(EXIT_FAILURE);
+    }
+    return res;
+}
+#undef  strdup
+#define strdup(_p) ao_strdup(_p)
+
+#ifndef HAVE_PATHFIND
+#  include "compat/pathfind.c"
+#endif
+
+#ifndef HAVE_SNPRINTF
+#  include "compat/snprintf.c"
+#endif
+
+#ifndef HAVE_STRDUP
+#  include "compat/strdup.c"
+#endif
+
+#ifndef HAVE_STRCHR
+#  include "compat/strchr.c"
+#endif
+
+/*
+ *  handle_opt
+ *
+ *  This routine handles equivalencing, sets the option state flags and
+ *  invokes the handler procedure, if any.
+ */
+LOCAL tSuccess
+handle_opt(tOptions * pOpts, tOptState* pOptState)
+{
+    /*
+     *  Save a copy of the option procedure pointer.
+     *  If this is an equivalence class option, we still want this proc.
+     */
+    tOptDesc* pOD = pOptState->pOD;
+    tOptProc* pOP = pOD->pOptProc;
+    if (pOD->fOptState & OPTST_ALLOC_ARG)
+        AGFREE(pOD->optArg.argString);
+
+    pOD->optArg.argString = pOptState->pzOptArg;
+
+    /*
+     *  IF we are presetting options, then we will ignore any un-presettable
+     *  options.  They are the ones either marked as such.
+     */
+    if (  ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0)
+       && ((pOD->fOptState & OPTST_NO_INIT) != 0)
+       )
+        return PROBLEM;
+
+    /*
+     *  IF this is an equivalence class option,
+     *  THEN
+     *      Save the option value that got us to this option
+     *      entry.  (It may not be pOD->optChar[0], if this is an
+     *      equivalence entry.)
+     *      set the pointer to the equivalence class base
+     */
+    if (pOD->optEquivIndex != NO_EQUIVALENT) {
+        tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex;
+
+        /*
+         * IF the current option state has not been defined (set on the
+         *    command line), THEN we will allow continued resetting of
+         *    the value.  Once "defined", then it must not change.
+         */
+        if ((pOD->fOptState & OPTST_DEFINED) != 0) {
+            /*
+             *  The equivalenced-to option has been found on the command
+             *  line before.  Make sure new occurrences are the same type.
+             *
+             *  IF this option has been previously equivalenced and
+             *     it was not the same equivalenced-to option,
+             *  THEN we have a usage problem.
+             */
+            if (p->optActualIndex != pOD->optIndex) {
+                fprintf(stderr, (char*)zMultiEquiv, p->pz_Name, pOD->pz_Name,
+                        (pOpts->pOptDesc + p->optActualIndex)->pz_Name);
+                return FAILURE;
+            }
+        } else {
+            /*
+             *  Set the equivalenced-to actual option index to no-equivalent
+             *  so that we set all the entries below.  This option may either
+             *  never have been selected before, or else it was selected by
+             *  some sort of "presetting" mechanism.
+             */
+            p->optActualIndex = NO_EQUIVALENT;
+        }
+
+        if (p->optActualIndex != pOD->optIndex) {
+            /*
+             *  First time through, copy over the state
+             *  and add in the equivalence flag
+             */
+            p->optActualValue = pOD->optValue;
+            p->optActualIndex = pOD->optIndex;
+            pOptState->flags |= OPTST_EQUIVALENCE;
+        }
+
+        /*
+         *  Copy the most recent option argument.  set membership state
+         *  is kept in ``p->optCookie''.  Do not overwrite.
+         */
+        p->optArg.argString = pOD->optArg.argString;
+        pOD = p;
+
+    } else {
+        pOD->optActualValue = pOD->optValue;
+        pOD->optActualIndex = pOD->optIndex;
+    }
+
+    pOD->fOptState &= OPTST_PERSISTENT_MASK;
+    pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK);
+
+    /*
+     *  Keep track of count only for DEFINED (command line) options.
+     *  IF we have too many, build up an error message and bail.
+     */
+    if (  (pOD->fOptState & OPTST_DEFINED)
+       && (++pOD->optOccCt > pOD->optMaxCt)  )  {
+
+        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+            char const * pzEqv =
+                (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil;
+
+            fputs(zErrOnly, stderr);
+
+            if (pOD->optMaxCt > 1)
+                fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv);
+            else
+                fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv);
+        }
+
+        return FAILURE;
+    }
+
+    /*
+     *  If provided a procedure to call, call it
+     */
+    if (pOP != NULL)
+        (*pOP)(pOpts, pOD);
+
+    return SUCCESS;
+}
+
+static tSuccess
+next_opt_arg_must(tOptions * pOpts, tOptState* pOptState)
+{
+    /*
+     *  An option argument is required.  Long options can either have
+     *  a separate command line argument, or an argument attached by
+     *  the '=' character.  Figure out which.
+     */
+    switch (pOptState->optType) {
+    case TOPT_SHORT:
+        /*
+         *  See if an arg string follows the flag character
+         */
+        if (*++(pOpts->pzCurOpt) == NUL)
+            pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx++ ];
+        pOptState->pzOptArg = pOpts->pzCurOpt;
+        break;
+
+    case TOPT_LONG:
+        /*
+         *  See if an arg string has already been assigned (glued on
+         *  with an `=' character)
+         */
+        if (pOptState->pzOptArg == NULL)
+            pOptState->pzOptArg = pOpts->origArgVect[ pOpts->curOptIdx++ ];
+        break;
+
+    default:
+#ifdef DEBUG
+        fputs("AutoOpts lib error: option type not selected\n", stderr);
+        exit(EXIT_FAILURE);
+#endif
+
+    case TOPT_DEFAULT:
+        /*
+         *  The option was selected by default.  The current token is
+         *  the option argument.
+         */
+        break;
+    }
+
+    /*
+     *  Make sure we did not overflow the argument list.
+     */
+    if (pOpts->curOptIdx > pOpts->origArgCt) {
+        fprintf(stderr, zMisArg, pOpts->pzProgPath, pOptState->pOD->pz_Name);
+        return FAILURE;
+    }
+
+    pOpts->pzCurOpt = NULL;  /* next time advance to next arg */
+    return SUCCESS;
+}
+
+
+static tSuccess
+next_opt_arg_may(tOptions * pOpts, tOptState* pOptState)
+{
+    /*
+     *  An option argument is optional.
+     */
+    switch (pOptState->optType) {
+    case TOPT_SHORT:
+        if (*++pOpts->pzCurOpt != NUL)
+            pOptState->pzOptArg = pOpts->pzCurOpt;
+        else {
+            char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
+
+            /*
+             *  BECAUSE it is optional, we must make sure
+             *  we did not find another flag and that there
+             *  is such an argument.
+             */
+            if ((pzLA == NULL) || (*pzLA == '-'))
+                pOptState->pzOptArg = NULL;
+            else {
+                pOpts->curOptIdx++; /* argument found */
+                pOptState->pzOptArg = pzLA;
+            }
+        }
+        break;
+
+    case TOPT_LONG:
+        /*
+         *  Look for an argument if we don't already have one (glued on
+         *  with a `=' character) *AND* we are not in named argument mode
+         */
+        if (  (pOptState->pzOptArg == NULL)
+           && (! NAMED_OPTS(pOpts))) {
+            char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
+
+            /*
+             *  BECAUSE it is optional, we must make sure
+             *  we did not find another flag and that there
+             *  is such an argument.
+             */
+            if ((pzLA == NULL) || (*pzLA == '-'))
+                pOptState->pzOptArg = NULL;
+            else {
+                pOpts->curOptIdx++; /* argument found */
+                pOptState->pzOptArg = pzLA;
+            }
+        }
+        break;
+
+    default:
+    case TOPT_DEFAULT:
+        fputs(zAO_Woops, stderr );
+        exit(EX_SOFTWARE);
+    }
+
+    /*
+     *  After an option with an optional argument, we will
+     *  *always* start with the next option because if there
+     *  were any characters following the option name/flag,
+     *  they would be interpreted as the argument.
+     */
+    pOpts->pzCurOpt = NULL;
+    return SUCCESS;
+}
+
+
+static tSuccess
+next_opt_arg_none(tOptions * pOpts, tOptState* pOptState)
+{
+    /*
+     *  No option argument.  Make sure next time around we find
+     *  the correct option flag character for short options
+     */
+    if (pOptState->optType == TOPT_SHORT)
+        (pOpts->pzCurOpt)++;
+
+    /*
+     *  It is a long option.  Make sure there was no ``=xxx'' argument
+     */
+    else if (pOptState->pzOptArg != NULL) {
+        fprintf(stderr, zNoArg, pOpts->pzProgPath, pOptState->pOD->pz_Name);
+        return FAILURE;
+    }
+
+    /*
+     *  It is a long option.  Advance to next command line argument.
+     */
+    else
+        pOpts->pzCurOpt = NULL;
+    return SUCCESS;
+}
+
+/**
+ *  Find the option descriptor and option argument (if any) for the
+ *  next command line argument.  DO NOT modify the descriptor.  Put
+ *  all the state in the state argument so that the option can be skipped
+ *  without consequence (side effect).
+ *
+ * @param pOpts     the program option descriptor
+ * @param pOptState the state of the next found option
+ */
+static tSuccess
+next_opt(tOptions * pOpts, tOptState * pOptState)
+{
+    {
+        tSuccess res = find_opt(pOpts, pOptState);
+        if (! SUCCESSFUL(res))
+            return res;
+    }
+
+    if (  ((pOptState->flags & OPTST_DEFINED) != 0)
+       && ((pOptState->pOD->fOptState & OPTST_NO_COMMAND) != 0)) {
+        fprintf(stderr, zNotCmdOpt, pOptState->pOD->pz_Name);
+        return FAILURE;
+    }
+
+    return get_opt_arg(pOpts, pOptState);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  DO PRESETS
+ *
+ *  The next several routines do the immediate action pass on the command
+ *  line options, then the environment variables, then the config files in
+ *  reverse order.  Once done with that, the order is reversed and all
+ *  the config files and environment variables are processed again, this
+ *  time only processing the non-immediate action options.  doPresets()
+ *  will then return for optionProcess() to do the final pass on the command
+ *  line arguments.
+ */
+
+/**
+ *  scan the command line for immediate action options.
+ *  This is only called the first time through.
+ *  While this procedure is active, the OPTPROC_IMMEDIATE is true.
+ *
+ *  @param pOpts   program options descriptor
+ *  @returns SUCCESS or FAILURE
+ */
+LOCAL tSuccess
+immediate_opts(tOptions * pOpts)
+{
+    tSuccess  res;
+
+    pOpts->fOptSet  |= OPTPROC_IMMEDIATE;
+    pOpts->curOptIdx = 1;     /* start by skipping program name */
+    pOpts->pzCurOpt  = NULL;
+
+    /*
+     *  Examine all the options from the start.  We process any options that
+     *  are marked for immediate processing.
+     */
+    for (;;) {
+        tOptState optState = OPTSTATE_INITIALIZER(PRESET);
+
+        res = next_opt(pOpts, &optState);
+        switch (res) {
+        case FAILURE: goto   failed_option;
+        case PROBLEM: res = SUCCESS; goto leave;
+        case SUCCESS: break;
+        }
+
+        /*
+         *  IF this is an immediate-attribute option, then do it.
+         */
+        if (! DO_IMMEDIATELY(optState.flags))
+            continue;
+
+        if (! SUCCESSFUL(handle_opt(pOpts, &optState)))
+            break;
+    } failed_option:;
+
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
+        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+
+leave:
+
+    pOpts->fOptSet &= ~OPTPROC_IMMEDIATE;
+    return res;
+}
+
+/**
+ * Process all the options from our current position onward.  (This allows
+ * interspersed options and arguments for the few non-standard programs that
+ * require it.)  Thus, do not rewind option indexes because some programs
+ * choose to re-invoke after a non-option.
+ *
+ *  @param pOpts   program options descriptor
+ *  @returns SUCCESS or FAILURE
+ */
+LOCAL tSuccess
+regular_opts(tOptions * pOpts)
+{
+    /* assert:  pOpts->fOptSet & OPTPROC_IMMEDIATE == 0 */
+    for (;;) {
+        tOptState optState = OPTSTATE_INITIALIZER(DEFINED);
+
+        switch (next_opt(pOpts, &optState)) {
+        case FAILURE: goto   failed_option;
+        case PROBLEM: return SUCCESS; /* no more args */
+        case SUCCESS: break;
+        }
+
+        /*
+         *  IF this is an immediate action option,
+         *  THEN skip it (unless we are supposed to do it a second time).
+         */
+        if (! DO_NORMALLY(optState.flags)) {
+            if (! DO_SECOND_TIME(optState.flags))
+                continue;
+            optState.pOD->optOccCt--; /* don't count this repetition */
+        }
+
+        if (! SUCCESSFUL(handle_opt(pOpts, &optState)))
+            break;
+    } failed_option:;
+
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
+        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+
+    return FAILURE;
+}
+
+
+/**
+ *  check for preset values from a config files or envrionment variables
+ */
+static tSuccess
+doPresets(tOptions * pOpts)
+{
+    tOptDesc * pOD = NULL;
+
+    if (! SUCCESSFUL(immediate_opts(pOpts)))
+        return FAILURE;
+
+    /*
+     *  IF this option set has a --save-opts option, then it also
+     *  has a --load-opts option.  See if a command line option has disabled
+     *  option presetting.
+     */
+    if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
+       && (pOpts->specOptIdx.save_opts != 0)) {
+        pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
+        if (DISABLED_OPT(pOD))
+            return SUCCESS;
+    }
+
+    /*
+     *  Until we return from this procedure, disable non-presettable opts
+     */
+    pOpts->fOptSet |= OPTPROC_PRESETTING;
+    /*
+     *  IF there are no config files,
+     *  THEN do any environment presets and leave.
+     */
+    if (pOpts->papzHomeList == NULL) {
+        env_presets(pOpts, ENV_ALL);
+    }
+    else {
+        env_presets(pOpts, ENV_IMM);
+
+        /*
+         *  Check to see if environment variables have disabled presetting.
+         */
+        if ((pOD != NULL) && ! DISABLED_OPT(pOD))
+            intern_file_load(pOpts);
+
+        /*
+         *  ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment
+         *  variable options.  Only the loading of .rc files.
+         */
+        env_presets(pOpts, ENV_NON_IMM);
+    }
+    pOpts->fOptSet &= ~OPTPROC_PRESETTING;
+
+    return SUCCESS;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE
+ */
+/*=--subblock=arg=arg_type,arg_name,arg_desc =*/
+/*=*
+ * library:  opts
+ * header:   your-opts.h
+ *
+ * lib_description:
+ *
+ *  These are the routines that libopts users may call directly from their
+ *  code.  There are several other routines that can be called by code
+ *  generated by the libopts option templates, but they are not to be
+ *  called from any other user code.  The @file{options.h} header is
+ *  fairly clear about this, too.
+=*/
+
+/*=export_func optionProcess
+ *
+ * what: this is the main option processing routine
+ *
+ * arg:  + tOptions* + pOpts + program options descriptor +
+ * arg:  + int       + argc  + program arg count  +
+ * arg:  + char**    + argv  + program arg vector +
+ *
+ * ret_type:  int
+ * ret_desc:  the count of the arguments processed
+ *
+ * doc:
+ *
+ * This is the main entry point for processing options.  It is intended
+ * that this procedure be called once at the beginning of the execution of
+ * a program.  Depending on options selected earlier, it is sometimes
+ * necessary to stop and restart option processing, or to select completely
+ * different sets of options.  This can be done easily, but you generally
+ * do not want to do this.
+ *
+ * The number of arguments processed always includes the program name.
+ * If one of the arguments is "--", then it is counted and the processing
+ * stops.  If an error was encountered and errors are to be tolerated, then
+ * the returned value is the index of the argument causing the error.
+ * A hyphen by itself ("-") will also cause processing to stop and will
+ * @emph{not} be counted among the processed arguments.  A hyphen by itself
+ * is treated as an operand.  Encountering an operand stops option
+ * processing.
+ *
+ * err:  Errors will cause diagnostics to be printed.  @code{exit(3)} may
+ *       or may not be called.  It depends upon whether or not the options
+ *       were generated with the "allow-errors" attribute, or if the
+ *       ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked.
+=*/
+int
+optionProcess(tOptions * pOpts, int argCt, char ** argVect)
+{
+    if (! SUCCESSFUL(validate_struct(pOpts, argVect[0])))
+        exit(EX_SOFTWARE);
+
+    /*
+     *  Establish the real program name, the program full path,
+     *  and do all the presetting the first time thru only.
+     */
+    if ((pOpts->fOptSet & OPTPROC_INITDONE) == 0) {
+        pOpts->origArgCt   = argCt;
+        pOpts->origArgVect = argVect;
+        pOpts->fOptSet    |= OPTPROC_INITDONE;
+        if (HAS_pzPkgDataDir(pOpts))
+            program_pkgdatadir = pOpts->pzPkgDataDir;
+
+        if (! SUCCESSFUL(doPresets(pOpts)))
+            return 0;
+
+        /*
+         *  IF option name conversion was suppressed but it is not suppressed
+         *  for the command line, then it's time to translate option names.
+         *  Usage text will not get retranslated.
+         */
+        if (  ((pOpts->fOptSet & OPTPROC_TRANSLATE) != 0)
+           && (pOpts->pTransProc != NULL)
+           && ((pOpts->fOptSet & OPTPROC_NO_XLAT_MASK)
+              == OPTPROC_NXLAT_OPT_CFG)  )  {
+
+            pOpts->fOptSet &= ~OPTPROC_NXLAT_OPT_CFG;
+            (*pOpts->pTransProc)();
+        }
+
+        if ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
+            optionSort(pOpts);
+
+        pOpts->curOptIdx   = 1;
+        pOpts->pzCurOpt    = NULL;
+    }
+
+    /*
+     *  IF we are (re)starting,
+     *  THEN reset option location
+     */
+    else if (pOpts->curOptIdx <= 0) {
+        pOpts->curOptIdx = 1;
+        pOpts->pzCurOpt  = NULL;
+    }
+
+    if (! SUCCESSFUL(regular_opts(pOpts)))
+        return pOpts->origArgCt;
+
+    /*
+     *  IF    there were no errors
+     *    AND we have RC/INI files
+     *    AND there is a request to save the files
+     *  THEN do that now before testing for conflicts.
+     *       (conflicts are ignored in preset options)
+     */
+    if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
+       && (pOpts->specOptIdx.save_opts != 0)) {
+        tOptDesc*  pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts;
+
+        if (SELECTED_OPT(pOD)) {
+            optionSaveFile(pOpts);
+            exit(EXIT_SUCCESS);
+        }
+    }
+
+    /*
+     *  IF we are checking for errors,
+     *  THEN look for too few occurrences of required options
+     */
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+        if (! is_consistent(pOpts))
+            (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+    }
+
+    return pOpts->curOptIdx;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/autoopts.c */
diff --git a/libopts/autoopts.h b/libopts/autoopts.h
new file mode 100644 (file)
index 0000000..831a52b
--- /dev/null
@@ -0,0 +1,334 @@
+
+/*
+ *  \file autoopts.h
+ *
+ *  Time-stamp:      "2011-03-25 17:51:34 bkorb"
+ *
+ *  This file defines all the global structures and special values
+ *  used in the automated option processing library.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+#ifndef AUTOGEN_AUTOOPTS_H
+#define AUTOGEN_AUTOOPTS_H
+
+#include "compat/compat.h"
+#include "ag-char-map.h"
+
+#define AO_NAME_LIMIT           127
+#define AO_NAME_SIZE            ((size_t)(AO_NAME_LIMIT + 1))
+
+#ifndef AG_PATH_MAX
+#  ifdef PATH_MAX
+#    define AG_PATH_MAX         ((size_t)PATH_MAX)
+#  else
+#    define AG_PATH_MAX         ((size_t)4096)
+#  endif
+#else
+#  if defined(PATH_MAX) && (PATH_MAX > MAXPATHLEN)
+#     undef  AG_PATH_MAX
+#     define AG_PATH_MAX        ((size_t)PATH_MAX)
+#  endif
+#endif
+
+#undef  EXPORT
+#define EXPORT
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define DIRCH                  '\\'
+#else
+# define DIRCH                  '/'
+#endif
+
+#ifndef EX_NOINPUT
+#  define EX_NOINPUT            66
+#endif
+#ifndef EX_SOFTWARE
+#  define EX_SOFTWARE           70
+#endif
+#ifndef EX_CONFIG
+#  define EX_CONFIG             78
+#endif
+
+/*
+ *  Convert the number to a list usable in a printf call
+ */
+#define NUM_TO_VER(n)           ((n) >> 12), ((n) >> 7) & 0x001F, (n) & 0x007F
+
+#define NAMED_OPTS(po) \
+        (((po)->fOptSet & (OPTPROC_SHORTOPT | OPTPROC_LONGOPT)) == 0)
+
+#define SKIP_OPT(p)  (((p)->fOptState & (OPTST_DOCUMENT|OPTST_OMITTED)) != 0)
+
+typedef int tDirection;
+#define DIRECTION_PRESET        -1
+#define DIRECTION_PROCESS       1
+#define DIRECTION_CALLED        0
+
+#define PROCESSING(d)           ((d)>0)
+#define PRESETTING(d)           ((d)<0)
+
+/*
+ *  When loading a line (or block) of text as an option, the value can
+ *  be processed in any of several modes:
+ *
+ *  @table @samp
+ *  @item keep
+ *  Every part of the value between the delimiters is saved.
+ *
+ *  @item uncooked
+ *  Even if the value begins with quote characters, do not do quote processing.
+ *
+ *  @item cooked
+ *  If the value looks like a quoted string, then process it.
+ *  Double quoted strings are processed the way strings are in "C" programs,
+ *  except they are treated as regular characters if the following character
+ *  is not a well-established escape sequence.
+ *  Single quoted strings (quoted with apostrophies) are handled the way
+ *  strings are handled in shell scripts, *except* that backslash escapes
+ *  are honored before backslash escapes and apostrophies.
+ *  @end table
+ */
+typedef enum {
+    OPTION_LOAD_COOKED,
+    OPTION_LOAD_UNCOOKED,
+    OPTION_LOAD_KEEP
+} tOptionLoadMode;
+
+static tOptionLoadMode option_load_mode;
+
+/*
+ *  The pager state is used by optionPagedUsage() procedure.
+ *  When it runs, it sets itself up to be called again on exit.
+ *  If, however, a routine needs a child process to do some work
+ *  before it is done, then 'pagerState' must be set to
+ *  'PAGER_STATE_CHILD' so that optionPagedUsage() will not try
+ *  to run the pager program before its time.
+ */
+typedef enum {
+    PAGER_STATE_INITIAL,
+    PAGER_STATE_READY,
+    PAGER_STATE_CHILD
+} tePagerState;
+
+typedef enum {
+    ENV_ALL,
+    ENV_IMM,
+    ENV_NON_IMM
+} teEnvPresetType;
+
+typedef enum {
+    TOPT_UNDEFINED = 0,
+    TOPT_SHORT,
+    TOPT_LONG,
+    TOPT_DEFAULT
+} teOptType;
+
+typedef struct {
+    tOptDesc*  pOD;
+    tCC*       pzOptArg;
+    tAoUL      flags;
+    teOptType  optType;
+} tOptState;
+#define OPTSTATE_INITIALIZER(st) \
+    { NULL, NULL, OPTST_ ## st, TOPT_UNDEFINED }
+
+#define TEXTTO_TABLE \
+        _TT_(LONGUSAGE) \
+        _TT_(USAGE) \
+        _TT_(VERSION)
+#define _TT_(n) \
+        TT_ ## n ,
+
+typedef enum { TEXTTO_TABLE COUNT_TT } teTextTo;
+
+#undef _TT_
+
+typedef struct {
+    char const * pzStr;
+    char const * pzReq;
+    char const * pzNum;
+    char const * pzFile;
+    char const * pzKey;
+    char const * pzKeyL;
+    char const * pzBool;
+    char const * pzNest;
+    char const * pzOpt;
+    char const * pzNo;
+    char const * pzBrk;
+    char const * pzNoF;
+    char const * pzSpc;
+    char const * pzOptFmt;
+    char const * pzTime;
+} arg_types_t;
+
+#define AGALOC(c, w)          ao_malloc((size_t)c)
+#define AGREALOC(p, c, w)     ao_realloc((void*)p, (size_t)c)
+#define AGFREE(_p)            free((void *)_p)
+#define AGDUPSTR(p, s, w)     (p = ao_strdup(s))
+
+static void *
+ao_malloc(size_t sz);
+
+static void *
+ao_realloc(void *p, size_t sz);
+
+#define ao_free(_p) free((void *)_p)
+
+static char *
+ao_strdup(char const *str);
+
+#define TAGMEM(m, t)
+
+/*
+ *  DO option handling?
+ *
+ *  Options are examined at two times:  at immediate handling time and at
+ *  normal handling time.  If an option is disabled, the timing may be
+ *  different from the handling of the undisabled option.  The OPTST_DIABLED
+ *  bit indicates the state of the currently discovered option.
+ *  So, here's how it works:
+ *
+ *  A) handling at "immediate" time, either 1 or 2:
+ *
+ *  1.  OPTST_DISABLED is not set:
+ *      IMM           must be set
+ *      DISABLE_IMM   don't care
+ *      TWICE         don't care
+ *      DISABLE_TWICE don't care
+ *      0 -and-  1 x x x
+ *
+ *  2.  OPTST_DISABLED is set:
+ *      IMM           don't care
+ *      DISABLE_IMM   must be set
+ *      TWICE         don't care
+ *      DISABLE_TWICE don't care
+ *      1 -and-  x 1 x x
+ */
+#define DO_IMMEDIATELY(_flg) \
+    (  (((_flg) & (OPTST_DISABLED|OPTST_IMM)) == OPTST_IMM) \
+    || (   ((_flg) & (OPTST_DISABLED|OPTST_DISABLE_IMM))    \
+        == (OPTST_DISABLED|OPTST_DISABLE_IMM)  ))
+
+/*  B) handling at "regular" time because it was not immediate
+ *
+ *  1.  OPTST_DISABLED is not set:
+ *      IMM           must *NOT* be set
+ *      DISABLE_IMM   don't care
+ *      TWICE         don't care
+ *      DISABLE_TWICE don't care
+ *      0 -and-  0 x x x
+ *
+ *  2.  OPTST_DISABLED is set:
+ *      IMM           don't care
+ *      DISABLE_IMM   don't care
+ *      TWICE         must be set
+ *      DISABLE_TWICE don't care
+ *      1 -and-  x x 1 x
+ */
+#define DO_NORMALLY(_flg) ( \
+       (((_flg) & (OPTST_DISABLED|OPTST_IMM))            == 0)  \
+    || (((_flg) & (OPTST_DISABLED|OPTST_DISABLE_IMM))    ==     \
+                  OPTST_DISABLED)  )
+
+/*  C)  handling at "regular" time because it is to be handled twice.
+ *      The immediate bit was already tested and found to be set:
+ *
+ *  3.  OPTST_DISABLED is not set:
+ *      IMM           is set (but don't care)
+ *      DISABLE_IMM   don't care
+ *      TWICE         must be set
+ *      DISABLE_TWICE don't care
+ *      0 -and-  ? x 1 x
+ *
+ *  4.  OPTST_DISABLED is set:
+ *      IMM           don't care
+ *      DISABLE_IMM   is set (but don't care)
+ *      TWICE         don't care
+ *      DISABLE_TWICE must be set
+ *      1 -and-  x ? x 1
+ */
+#define DO_SECOND_TIME(_flg) ( \
+       (((_flg) & (OPTST_DISABLED|OPTST_TWICE))          ==     \
+                  OPTST_TWICE)                                  \
+    || (((_flg) & (OPTST_DISABLED|OPTST_DISABLE_TWICE))  ==     \
+                  (OPTST_DISABLED|OPTST_DISABLE_TWICE)  ))
+
+/*
+ *  text_mmap structure.  Only active on platforms with mmap(2).
+ */
+#ifdef HAVE_SYS_MMAN_H
+#  include <sys/mman.h>
+#else
+#  ifndef  PROT_READ
+#   define PROT_READ            0x01
+#  endif
+#  ifndef  PROT_WRITE
+#   define PROT_WRITE           0x02
+#  endif
+#  ifndef  MAP_SHARED
+#   define MAP_SHARED           0x01
+#  endif
+#  ifndef  MAP_PRIVATE
+#   define MAP_PRIVATE          0x02
+#  endif
+#endif
+
+#ifndef MAP_FAILED
+#  define  MAP_FAILED           ((void*)-1)
+#endif
+
+#ifndef  _SC_PAGESIZE
+# ifdef  _SC_PAGE_SIZE
+#  define _SC_PAGESIZE          _SC_PAGE_SIZE
+# endif
+#endif
+
+#ifndef HAVE_STRCHR
+extern char* strchr(char const *s, int c);
+extern char* strrchr(char const *s, int c);
+#endif
+
+/*
+ *  Define and initialize all the user visible strings.
+ *  We do not do translations.  If translations are to be done, then
+ *  the client will provide a callback for that purpose.
+ */
+#undef DO_TRANSLATIONS
+#include "autoopts/usage-txt.h"
+
+/*
+ *  File pointer for usage output
+ */
+FILE * option_usage_fp;
+static char const * program_pkgdatadir;
+
+extern tOptProc optionPrintVersion, optionPagedUsage, optionLoadOpt;
+
+#endif /* AUTOGEN_AUTOOPTS_H */
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/autoopts.h */
diff --git a/libopts/autoopts/options.h b/libopts/autoopts/options.h
new file mode 100644 (file)
index 0000000..1e59faa
--- /dev/null
@@ -0,0 +1,1076 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (options.h)
+ *  
+ *  It has been AutoGen-ed  December 29, 2011 at 12:02:36 PM by AutoGen 5.14
+ *  From the definitions    funcs.def
+ *  and the template file   options_h
+ *
+ *  This file defines all the global structures and special values
+ *  used in the automated option processing library.
+ *
+ *  Automated Options Copyright (C) 1992-2011 by Bruce Korb
+ *
+ *   *  AutoOpts is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU Lesser General Public License as published
+ *  by the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  AutoOpts is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU Lesser General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.";
+ */
+#ifndef AUTOOPTS_OPTIONS_H_GUARD
+#define AUTOOPTS_OPTIONS_H_GUARD 1
+#include <sys/types.h>
+#include <stdio.h>
+
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif /* HAVE_STDINT/INTTYPES_H */
+
+#if defined(HAVE_LIMITS_H)
+# include <limits.h>
+#elif defined(HAVE_SYS_LIMITS_H)
+# include <sys/limits.h>
+#endif /* HAVE_LIMITS/SYS_LIMITS_H */
+
+#if defined(HAVE_SYSEXITS_H)
+#  include <sysexits.h>
+#endif /* HAVE_SYSEXITS_H */
+// END-CONFIGURED-HEADERS
+#ifndef  EX_USAGE
+# define EX_USAGE               64
+#endif
+
+/*
+ *  PUBLIC DEFINES
+ *
+ *  The following defines may be used in applications that need to test the
+ *  state of an option.  To test against these masks and values, a pointer
+ *  to an option descriptor must be obtained.  There are two ways:
+ *
+ *  1. inside an option processing procedure, it is the second argument,
+ *     conventionally "tOptDesc* pOD".
+ *
+ *  2. Outside of an option procedure (or to reference a different option
+ *     descriptor), use either "&DESC( opt_name )" or "&pfx_DESC( opt_name )".
+ *
+ *  See the relevant generated header file to determine which and what
+ *  values for "opt_name" are available.
+ */
+#define OPTIONS_STRUCT_VERSION      147457
+#define OPTIONS_VERSION_STRING      "36:1:11"
+#define OPTIONS_MINIMUM_VERSION     102400
+#define OPTIONS_MIN_VER_STRING      "25:0:0"
+#define OPTIONS_VER_TO_NUM(_v, _r)  (((_v) * 4096) + (_r))
+       
+typedef enum {
+    OPARG_TYPE_NONE             =  0,
+    OPARG_TYPE_STRING           =  1,    /* default type/ vanilla string      */
+    OPARG_TYPE_ENUMERATION      =  2,    /* opt arg is an enum (keyword list) */
+    OPARG_TYPE_BOOLEAN          =  3,    /* opt arg is boolean-valued         */
+    OPARG_TYPE_MEMBERSHIP       =  4,    /* opt arg sets set membership bits  */
+    OPARG_TYPE_NUMERIC          =  5,    /* opt arg is a long int             */
+    OPARG_TYPE_HIERARCHY        =  6,    /* option arg is hierarchical value  */
+    OPARG_TYPE_FILE             =  7,    /* option arg names a file           */
+    OPARG_TYPE_TIME             =  8,    /* opt arg is a time duration        */
+    OPARG_TYPE_FLOAT            =  9,    /* opt arg is a floating point num   */
+    OPARG_TYPE_DOUBLE           = 10,    /* opt arg is a double prec. float   */
+    OPARG_TYPE_LONG_DOUBLE      = 11,    /* opt arg is a long double prec.    */
+    OPARG_TYPE_LONG_LONG        = 12     /* opt arg is a long long int        */
+} teOptArgType;
+
+typedef struct optionValue {
+    teOptArgType        valType;
+    char*               pzName;
+    union {
+        char            strVal[1];      /* OPARG_TYPE_STRING      */
+        unsigned int    enumVal;        /* OPARG_TYPE_ENUMERATION */
+        unsigned int    boolVal;        /* OPARG_TYPE_BOOLEAN     */
+        unsigned long   setVal;         /* OPARG_TYPE_MEMBERSHIP  */
+        long            longVal;        /* OPARG_TYPE_NUMERIC     */
+        void*           nestVal;        /* OPARG_TYPE_HIERARCHY   */
+    } v;
+} tOptionValue;
+
+typedef enum {
+    FTYPE_MODE_MAY_EXIST        = 0x00,
+    FTYPE_MODE_MUST_EXIST       = 0x01,
+    FTYPE_MODE_MUST_NOT_EXIST   = 0x02,
+    FTYPE_MODE_EXIST_MASK       = 0x03,
+    FTYPE_MODE_NO_OPEN          = 0x00,
+    FTYPE_MODE_OPEN_FD          = 0x10,
+    FTYPE_MODE_FOPEN_FP         = 0x20,
+    FTYPE_MODE_OPEN_MASK        = 0x30
+} teOptFileType;
+
+typedef union {
+    int             file_flags;
+    char const *    file_mode;
+} tuFileMode;
+
+typedef struct argList tArgList;
+#define MIN_ARG_ALLOC_CT   6
+#define INCR_ARG_ALLOC_CT  8
+struct argList {
+    int             useCt;
+    int             allocCt;
+    char const *    apzArgs[MIN_ARG_ALLOC_CT];
+};
+
+/*
+ *  Bits in the fOptState option descriptor field.
+ */
+typedef enum {
+    OPTST_SET_ID             =   0, /* Set via the "SET_OPT()" macro */
+    OPTST_PRESET_ID          =   1, /* Set via an RC/INI file        */
+    OPTST_DEFINED_ID         =   2, /* Set via a command line option */
+    OPTST_RESET_ID           =   3, /* Reset via command line option */
+    OPTST_EQUIVALENCE_ID     =   4, /* selected by equiv'ed option   */
+    OPTST_DISABLED_ID        =   5, /* option is in disabled state   */
+    OPTST_ALLOC_ARG_ID       =   6, /* pzOptArg was allocated        */
+    OPTST_NO_INIT_ID         =   8, /* option cannot be preset       */
+    OPTST_NUMBER_OPT_ID      =   9, /* opt value (flag) is any digit */
+    OPTST_STACKED_ID         =  10, /* opt uses optionStackArg proc  */
+    OPTST_INITENABLED_ID     =  11, /* option defaults to enabled    */
+    OPTST_ARG_TYPE_1_ID      =  12, /* bit 1 of arg type enum        */
+    OPTST_ARG_TYPE_2_ID      =  13, /* bit 2 of arg type enum        */
+    OPTST_ARG_TYPE_3_ID      =  14, /* bit 3 of arg type enum        */
+    OPTST_ARG_TYPE_4_ID      =  15, /* bit 4 of arg type enum        */
+    OPTST_ARG_OPTIONAL_ID    =  16, /* the option arg not required   */
+    OPTST_IMM_ID             =  17, /* process opt on first pass     */
+    OPTST_DISABLE_IMM_ID     =  18, /* process disablement immed.    */
+    OPTST_OMITTED_ID         =  19, /* compiled out of program       */
+    OPTST_MUST_SET_ID        =  20, /* must be set or pre-set        */
+    OPTST_DOCUMENT_ID        =  21, /* opt is for doc only           */
+    OPTST_TWICE_ID           =  22, /* process opt twice - imm + reg */
+    OPTST_DISABLE_TWICE_ID   =  23, /* process disabled option twice */
+    OPTST_SCALED_NUM_ID      =  24, /* scaled integer value          */
+    OPTST_NO_COMMAND_ID      =  25, /* disable from cmd line         */
+    OPTST_DEPRECATED_ID      =  26  /* support is being removed      */
+} opt_state_enum_t;
+
+#define OPTST_INIT               0U
+#define OPTST_SET            (1U << OPTST_SET_ID)
+#define OPTST_PRESET         (1U << OPTST_PRESET_ID)
+#define OPTST_DEFINED        (1U << OPTST_DEFINED_ID)
+#define OPTST_RESET          (1U << OPTST_RESET_ID)
+#define OPTST_EQUIVALENCE    (1U << OPTST_EQUIVALENCE_ID)
+#define OPTST_DISABLED       (1U << OPTST_DISABLED_ID)
+#define OPTST_ALLOC_ARG      (1U << OPTST_ALLOC_ARG_ID)
+#define OPTST_NO_INIT        (1U << OPTST_NO_INIT_ID)
+#define OPTST_NUMBER_OPT     (1U << OPTST_NUMBER_OPT_ID)
+#define OPTST_STACKED        (1U << OPTST_STACKED_ID)
+#define OPTST_INITENABLED    (1U << OPTST_INITENABLED_ID)
+#define OPTST_ARG_TYPE_1     (1U << OPTST_ARG_TYPE_1_ID)
+#define OPTST_ARG_TYPE_2     (1U << OPTST_ARG_TYPE_2_ID)
+#define OPTST_ARG_TYPE_3     (1U << OPTST_ARG_TYPE_3_ID)
+#define OPTST_ARG_TYPE_4     (1U << OPTST_ARG_TYPE_4_ID)
+#define OPTST_ARG_OPTIONAL   (1U << OPTST_ARG_OPTIONAL_ID)
+#define OPTST_IMM            (1U << OPTST_IMM_ID)
+#define OPTST_DISABLE_IMM    (1U << OPTST_DISABLE_IMM_ID)
+#define OPTST_OMITTED        (1U << OPTST_OMITTED_ID)
+#define OPTST_MUST_SET       (1U << OPTST_MUST_SET_ID)
+#define OPTST_DOCUMENT       (1U << OPTST_DOCUMENT_ID)
+#define OPTST_TWICE          (1U << OPTST_TWICE_ID)
+#define OPTST_DISABLE_TWICE  (1U << OPTST_DISABLE_TWICE_ID)
+#define OPTST_SCALED_NUM     (1U << OPTST_SCALED_NUM_ID)
+#define OPTST_NO_COMMAND     (1U << OPTST_NO_COMMAND_ID)
+#define OPTST_DEPRECATED     (1U << OPTST_DEPRECATED_ID)
+#define OPT_STATE_MASK       0x07FFFF7FU
+
+#define OPTST_SET_MASK       ( \
+        OPTST_DEFINED | OPTST_PRESET |  OPTST_RESET | \
+        OPTST_SET \
+        /* 0x0000000FU */ )
+
+#define OPTST_MUTABLE_MASK   ( \
+        OPTST_ALLOC_ARG |   OPTST_DEFINED | \
+        OPTST_DISABLED |    OPTST_EQUIVALENCE | \
+        OPTST_PRESET |      OPTST_RESET | \
+        OPTST_SET \
+        /* 0x0000007FU */ )
+
+#define OPTST_SELECTED_MASK  ( \
+        OPTST_DEFINED | OPTST_SET \
+        /* 0x00000005U */ )
+
+#define OPTST_ARG_TYPE_MASK  ( \
+        OPTST_ARG_TYPE_1 | OPTST_ARG_TYPE_2 | OPTST_ARG_TYPE_3 | \
+        OPTST_ARG_TYPE_4 \
+        /* 0x0000F000U */ )
+
+#define OPTST_DO_NOT_SAVE_MASK   ( \
+        OPTST_DOCUMENT | OPTST_NO_INIT |  OPTST_OMITTED \
+        /* 0x00280100U */ )
+
+#define OPTST_NO_USAGE_MASK  ( \
+        OPTST_DEPRECATED | OPTST_NO_COMMAND | OPTST_OMITTED \
+        /* 0x06080000U */ )
+
+#ifdef NO_OPTIONAL_OPT_ARGS
+# undef  OPTST_ARG_OPTIONAL
+# define OPTST_ARG_OPTIONAL   0
+#endif
+
+#define VENDOR_OPTION_VALUE   'W'
+
+#define OPTST_PERSISTENT_MASK (~OPTST_MUTABLE_MASK)
+
+#define SELECTED_OPT(_od)     ((_od)->fOptState  & OPTST_SELECTED_MASK)
+#define UNUSED_OPT(  _od)     (((_od)->fOptState & OPTST_SET_MASK) == 0)
+#define DISABLED_OPT(_od)     ((_od)->fOptState  & OPTST_DISABLED)
+#define OPTION_STATE(_od)     ((_od)->fOptState)
+#define OPTST_SET_ARGTYPE(_n) ((_n) << OPTST_ARG_TYPE_1_ID)
+#define OPTST_GET_ARGTYPE(_f) (((_f)&OPTST_ARG_TYPE_MASK)>>OPTST_ARG_TYPE_1_ID)
+
+/*
+ *  PRIVATE INTERFACES
+ *
+ *  The following values are used in the generated code to communicate
+ *  with the option library procedures.  They are not for public use
+ *  and may be subject to change.
+ */
+
+/*
+ *  Define the processing state flags
+ */
+typedef enum {
+    OPTPROC_LONGOPT_ID         =   0, /* Process long style options     */
+    OPTPROC_SHORTOPT_ID        =   1, /* Process short style "flags"    */
+    OPTPROC_ERRSTOP_ID         =   2, /* Stop on argument errors        */
+    OPTPROC_DISABLEDOPT_ID     =   3, /* Current option is disabled     */
+    OPTPROC_NO_REQ_OPT_ID      =   4, /* no options are required        */
+    OPTPROC_NUM_OPT_ID         =   5, /* there is a number option       */
+    OPTPROC_INITDONE_ID        =   6, /* have inits been done?          */
+    OPTPROC_NEGATIONS_ID       =   7, /* any negation options?          */
+    OPTPROC_ENVIRON_ID         =   8, /* check environment?             */
+    OPTPROC_NO_ARGS_ID         =   9, /* Disallow remaining arguments   */
+    OPTPROC_ARGS_REQ_ID        =  10, /* Require args after options     */
+    OPTPROC_REORDER_ID         =  11, /* reorder operands after opts    */
+    OPTPROC_GNUUSAGE_ID        =  12, /* emit usage in GNU style        */
+    OPTPROC_TRANSLATE_ID       =  13, /* Translate strings in tOptions  */
+    OPTPROC_MISUSE_ID          =  14, /* no usage on usage error        */
+    OPTPROC_IMMEDIATE_ID       =  15, /* immediate options active       */
+    OPTPROC_NXLAT_OPT_CFG_ID   =  16, /* suppress for config only       */
+    OPTPROC_NXLAT_OPT_ID       =  17, /* suppress xlation always        */
+    OPTPROC_VENDOR_OPT_ID      =  18, /* vendor options active          */
+    OPTPROC_PRESETTING_ID      =  19  /* opt processing in preset state */
+} optproc_state_enum_t;
+
+#define OPTPROC_NONE               0U
+#define OPTPROC_LONGOPT        (1U << OPTPROC_LONGOPT_ID)
+#define OPTPROC_SHORTOPT       (1U << OPTPROC_SHORTOPT_ID)
+#define OPTPROC_ERRSTOP        (1U << OPTPROC_ERRSTOP_ID)
+#define OPTPROC_DISABLEDOPT    (1U << OPTPROC_DISABLEDOPT_ID)
+#define OPTPROC_NO_REQ_OPT     (1U << OPTPROC_NO_REQ_OPT_ID)
+#define OPTPROC_NUM_OPT        (1U << OPTPROC_NUM_OPT_ID)
+#define OPTPROC_INITDONE       (1U << OPTPROC_INITDONE_ID)
+#define OPTPROC_NEGATIONS      (1U << OPTPROC_NEGATIONS_ID)
+#define OPTPROC_ENVIRON        (1U << OPTPROC_ENVIRON_ID)
+#define OPTPROC_NO_ARGS        (1U << OPTPROC_NO_ARGS_ID)
+#define OPTPROC_ARGS_REQ       (1U << OPTPROC_ARGS_REQ_ID)
+#define OPTPROC_REORDER        (1U << OPTPROC_REORDER_ID)
+#define OPTPROC_GNUUSAGE       (1U << OPTPROC_GNUUSAGE_ID)
+#define OPTPROC_TRANSLATE      (1U << OPTPROC_TRANSLATE_ID)
+#define OPTPROC_MISUSE         (1U << OPTPROC_MISUSE_ID)
+#define OPTPROC_IMMEDIATE      (1U << OPTPROC_IMMEDIATE_ID)
+#define OPTPROC_NXLAT_OPT_CFG  (1U << OPTPROC_NXLAT_OPT_CFG_ID)
+#define OPTPROC_NXLAT_OPT      (1U << OPTPROC_NXLAT_OPT_ID)
+#define OPTPROC_VENDOR_OPT     (1U << OPTPROC_VENDOR_OPT_ID)
+#define OPTPROC_PRESETTING     (1U << OPTPROC_PRESETTING_ID)
+#define OPTPROC_STATE_MASK     0x000FFFFFU
+
+#define OPTPROC_NO_XLAT_MASK   ( \
+        OPTPROC_NXLAT_OPT |     OPTPROC_NXLAT_OPT_CFG \
+        /* 0x00030000U */ )
+
+#define STMTS(s)  do { s; } while (0)
+
+/*
+ *  The following must be #defined instead of typedef-ed
+ *  because "static const" cannot both be applied to a type,
+ *  tho each individually can...so they all are
+ */
+#define tSCC        static char const
+#define tCC         char const
+#define tAoSC       static char
+#define tAoUC       unsigned char
+#define tAoUI       unsigned int
+#define tAoUL       unsigned long
+#define tAoUS       unsigned short
+
+/*
+ *  It is so disgusting that there must be so many ways
+ *  of specifying TRUE and FALSE.
+ */
+typedef enum { AG_FALSE = 0, AG_TRUE } ag_bool;
+
+/*
+ *  Define a structure that describes each option and
+ *  a pointer to the procedure that handles it.
+ *  The argument is the count of this flag previously seen.
+ */
+typedef struct options  tOptions;
+typedef struct optDesc  tOptDesc;
+typedef struct optNames tOptNames;
+#define OPTPROC_EMIT_USAGE      ((tOptions *)0x01UL)
+#define OPTPROC_EMIT_SHELL      ((tOptions *)0x02UL)
+#define OPTPROC_RETURN_VALNAME  ((tOptions *)0x03UL)
+#define OPTPROC_EMIT_LIMIT      ((tOptions *)0x0FUL)
+
+/*
+ *  The option procedures do the special processing for each
+ *  option flag that needs it.
+ */
+typedef void (tOptProc)(tOptions*  pOpts, tOptDesc* pOptDesc);
+typedef tOptProc*  tpOptProc;
+
+/*
+ *  The usage procedure will never return.  It calls "exit(2)"
+ *  with the "exitCode" argument passed to it.
+ */
+// coverity[+kill]
+typedef void (tUsageProc)(tOptions* pOpts, int exitCode);
+typedef tUsageProc* tpUsageProc;
+
+/*
+ *  Special definitions.  "NOLIMIT" is the 'max' value to use when
+ *  a flag may appear multiple times without limit.  "NO_EQUIVALENT"
+ *  is an illegal value for 'optIndex' (option description index).
+ */
+#define NOLIMIT          USHRT_MAX
+#define OPTION_LIMIT     SHRT_MAX
+#define NO_EQUIVALENT    (OPTION_LIMIT+1)
+
+typedef union {
+    char const *    argString;
+    uintptr_t       argEnum;
+    uintptr_t       argIntptr;
+    long            argInt;
+    unsigned long   argUint;
+    unsigned int    argBool;
+    FILE *          argFp;
+    int             argFd;
+} optArgBucket_t;
+
+#define             pzLastArg   optArg.argString
+
+/*
+ *  Descriptor structure for each option.
+ *  Only the fields marked "PUBLIC" are for public use.
+ */
+struct optDesc {
+    tAoUS const     optIndex;         /* PUBLIC */
+    tAoUS const     optValue;         /* PUBLIC */
+    tAoUS           optActualIndex;   /* PUBLIC */
+    tAoUS           optActualValue;   /* PUBLIC */
+
+    tAoUS const     optEquivIndex;    /* PUBLIC */
+    tAoUS const     optMinCt;
+    tAoUS const     optMaxCt;
+    tAoUS           optOccCt;         /* PUBLIC */
+
+    tAoUI           fOptState;        /* PUBLIC */
+    tAoUI           reserved;
+    optArgBucket_t  optArg;           /* PUBLIC */
+    void*           optCookie;        /* PUBLIC */
+
+    int const * const   pOptMust;
+    int const * const   pOptCant;
+    tpOptProc   const   pOptProc;
+    char const* const   pzText;
+
+    char const* const   pz_NAME;
+    char const* const   pz_Name;
+    char const* const   pz_DisableName;
+    char const* const   pz_DisablePfx;
+};
+
+/*
+ *  Some options need special processing, so we store their
+ *  indexes in a known place:
+ */
+typedef struct optSpecIndex tOptSpecIndex;
+struct optSpecIndex {
+    const tAoUS         more_help;
+    const tAoUS         save_opts;
+    const tAoUS         number_option;
+    const tAoUS         default_opt;
+};
+
+/*
+ *  The procedure generated for translating option text
+ */
+typedef void (tOptionXlateProc)(void);
+
+/*
+ * Everything marked "PUBLIC" is also marked "const".  Public access is not
+ * a license to modify.  Other fields are used and modified by the library.
+ * They are also subject to change without any notice.
+ * Do not even look at these outside of libopts.
+ */
+struct options {
+    int const           structVersion;
+    int                 origArgCt;
+    char**              origArgVect;
+    unsigned int        fOptSet;
+    unsigned int        curOptIdx;
+    char*               pzCurOpt;
+
+    char const* const   pzProgPath;         /* PUBLIC */
+    char const* const   pzProgName;         /* PUBLIC */
+    char const* const   pzPROGNAME;         /* PUBLIC */
+    char const* const   pzRcName;           /* PUBLIC */
+    char const* const   pzCopyright;        /* PUBLIC */
+    char const* const   pzCopyNotice;       /* PUBLIC */
+    char const* const   pzFullVersion;      /* PUBLIC */
+    char const* const* const papzHomeList;
+    char const* const   pzUsageTitle;
+    char const* const   pzExplain;
+    char const* const   pzDetail;
+    tOptDesc*   const   pOptDesc;           /* PUBLIC */
+    char const* const   pzBugAddr;          /* PUBLIC */
+
+    void*               pExtensions;
+    void*               pSavedState;
+
+    // coverity[+kill]
+    tpUsageProc         pUsageProc;
+    tOptionXlateProc*   pTransProc;
+
+    tOptSpecIndex       specOptIdx;
+    int const           optCt;
+    int const           presetOptCt;
+    char const *        pzFullUsage;
+    char const *        pzShortUsage;
+    /* PUBLIC: */
+    optArgBucket_t const * const originalOptArgArray;
+    void * const * const originalOptArgCookie;
+    char const * const  pzPkgDataDir;
+    char const * const  pzPackager;
+};
+
+/*
+ *  Versions where in various fields first appear:
+ *  ($AO_CURRENT * 4096 + $AO_REVISION, but $AO_REVISION must be zero)
+ */
+#define originalOptArgArray_STRUCT_VERSION  131072 /* AO_CURRENT = 32 */
+#define HAS_originalOptArgArray(_opt) \
+    ((_opt)->structVersion >= originalOptArgArray_STRUCT_VERSION)
+
+#define pzPkgDataDir_STRUCT_VERSION  139264 /* AO_CURRENT = 34 */
+#define HAS_pzPkgDataDir(_opt) \
+    ((_opt)->structVersion >= pzPkgDataDir_STRUCT_VERSION)
+
+/*
+ *  "token list" structure returned by "string_tokenize()"
+ */
+typedef struct {
+    unsigned long   tkn_ct;
+    unsigned char*  tkn_list[1];
+} token_list_t;
+
+/*
+ *  Hide the interface - it pollutes a POSIX claim, but leave it for
+ *  anyone #include-ing this header
+ */
+#define strneqvcmp      option_strneqvcmp
+#define streqvcmp       option_streqvcmp
+#define streqvmap       option_streqvmap
+#define strequate       option_strequate
+#define strtransform    option_strtransform
+
+/**
+ *  Everything needed to be known about an mmap-ed file.
+ *
+ *  This is an output only structure used by text_mmap and text_munmap.
+ *  Clients must not alter the contents and must provide it to both
+ *  the text_mmap and text_munmap procedures.  BE ADVISED: if you are
+ *  mapping the file with PROT_WRITE the NUL byte at the end MIGHT NOT
+ *  BE WRITABLE.  In any event, that byte is not be written back
+ *  to the source file.  ALSO: if "txt_data" is valid and "txt_errno"
+ *  is not zero, then there *may* not be a terminating NUL.
+ */
+typedef struct {
+    void *      txt_data;      /*@< text file data   */
+    size_t      txt_size;      /*@< actual file size */
+    size_t      txt_full_size; /*@< mmaped mem size  */
+    int         txt_fd;        /*@< file descriptor  */
+    int         txt_zero_fd;   /*@< fd for /dev/zero */
+    int         txt_errno;     /*@< warning code     */
+    int         txt_prot;      /*@< "prot" flags     */
+    int         txt_flags;     /*@< mapping type     */
+} tmap_info_t;
+
+#define TEXT_MMAP_FAILED_ADDR(a)  ((void*)(a) ==  (void*)MAP_FAILED)
+
+#ifdef  __cplusplus
+#define CPLUSPLUS_OPENER extern "C" {
+CPLUSPLUS_OPENER
+#define CPLUSPLUS_CLOSER }
+#else
+#define CPLUSPLUS_CLOSER
+#endif
+
+/*
+ *  The following routines may be coded into AutoOpts client code:
+ */
+
+/* From: tokenize.c line 166
+ *
+ * ao_string_tokenize - tokenize an input string
+ *
+ * Arguments:
+ *   string       string to be tokenized
+ *
+ * Returns: token_list_t* - pointer to a structure that lists each token
+ *
+ *  This function will convert one input string into a list of strings.
+ *  The list of strings is derived by separating the input based on
+ *  white space separation.  However, if the input contains either single
+ *  or double quote characters, then the text after that character up to
+ *  a matching quote will become the string in the list.
+ *  
+ *  The returned pointer should be deallocated with @code{free(3C)} when
+ *  are done using the data.  The data are placed in a single block of
+ *  allocated memory.  Do not deallocate individual token/strings.
+ *  
+ *  The structure pointed to will contain at least these two fields:
+ *  @table @samp
+ *  @item tkn_ct
+ *  The number of tokens found in the input string.
+ *  @item tok_list
+ *  An array of @code{tkn_ct + 1} pointers to substring tokens, with
+ *  the last pointer set to NULL.
+ *  @end table
+ *  
+ *  There are two types of quoted strings: single quoted (@code{'}) and
+ *  double quoted (@code{"}).  Singly quoted strings are fairly raw in that
+ *  escape characters (@code{\\}) are simply another character, except when
+ *  preceding the following characters:
+ *  @example
+ *  @code{\\}  double backslashes reduce to one
+ *  @code{'}   incorporates the single quote into the string
+ *  @code{\n}  suppresses both the backslash and newline character
+ *  @end example
+ *  
+ *  Double quote strings are formed according to the rules of string
+ *  constants in ANSI-C programs.
+ */
+extern token_list_t* ao_string_tokenize(char const*);
+
+
+/* From: configfile.c line 77
+ *
+ * configFileLoad - parse a configuration file
+ *
+ * Arguments:
+ *   pzFile       the file to load
+ *
+ * Returns: const tOptionValue* - An allocated, compound value structure
+ *
+ *  This routine will load a named configuration file and parse the
+ *  text as a hierarchically valued option.  The option descriptor
+ *  created from an option definition file is not used via this interface.
+ *  The returned value is "named" with the input file name and is of
+ *  type "@code{OPARG_TYPE_HIERARCHY}".  It may be used in calls to
+ *  @code{optionGetValue()}, @code{optionNextValue()} and
+ *  @code{optionUnloadNested()}.
+ */
+extern const tOptionValue* configFileLoad(char const*);
+
+
+/* From: configfile.c line 1057
+ *
+ * optionFileLoad - Load the locatable config files, in order
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *   pzProg       program name
+ *
+ * Returns: int - 0 -> SUCCESS, -1 -> FAILURE
+ *
+ *  This function looks in all the specified directories for a configuration
+ *  file ("rc" file or "ini" file) and processes any found twice.  The first
+ *  time through, they are processed in reverse order (last file first).  At
+ *  that time, only "immediate action" configurables are processed.  For
+ *  example, if the last named file specifies not processing any more
+ *  configuration files, then no more configuration files will be processed.
+ *  Such an option in the @strong{first} named directory will have no effect.
+ *  
+ *  Once the immediate action configurables have been handled, then the
+ *  directories are handled in normal, forward order.  In that way, later
+ *  config files can override the settings of earlier config files.
+ *  
+ *  See the AutoOpts documentation for a thorough discussion of the
+ *  config file format.
+ *  
+ *  Configuration files not found or not decipherable are simply ignored.
+ */
+extern int optionFileLoad(tOptions*, char const*);
+
+
+/* From: configfile.c line 209
+ *
+ * optionFindNextValue - find a hierarcicaly valued option instance
+ *
+ * Arguments:
+ *   pOptDesc     an option with a nested arg type
+ *   pPrevVal     the last entry
+ *   name         name of value to find
+ *   value        the matching value
+ *
+ * Returns: const tOptionValue* - a compound value structure
+ *
+ *  This routine will find the next entry in a nested value option or
+ *  configurable.  It will search through the list and return the next entry
+ *  that matches the criteria.
+ */
+extern const tOptionValue* optionFindNextValue(const tOptDesc*, const tOptionValue*, char const*, char const*);
+
+
+/* From: configfile.c line 135
+ *
+ * optionFindValue - find a hierarcicaly valued option instance
+ *
+ * Arguments:
+ *   pOptDesc     an option with a nested arg type
+ *   name         name of value to find
+ *   value        the matching value
+ *
+ * Returns: const tOptionValue* - a compound value structure
+ *
+ *  This routine will find an entry in a nested value option or configurable.
+ *  It will search through the list and return a matching entry.
+ */
+extern const tOptionValue* optionFindValue(const tOptDesc*, char const*, char const*);
+
+
+/* From: restore.c line 166
+ *
+ * optionFree - free allocated option processing memory
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *
+ *  AutoOpts sometimes allocates memory and puts pointers to it in the
+ *  option state structures.  This routine deallocates all such memory.
+ */
+extern void optionFree(tOptions*);
+
+
+/* From: configfile.c line 278
+ *
+ * optionGetValue - get a specific value from a hierarcical list
+ *
+ * Arguments:
+ *   pOptValue    a hierarchcal value
+ *   valueName    name of value to get
+ *
+ * Returns: const tOptionValue* - a compound value structure
+ *
+ *  This routine will find an entry in a nested value option or configurable.
+ *  If "valueName" is NULL, then the first entry is returned.  Otherwise,
+ *  the first entry with a name that exactly matches the argument will be
+ *  returned.  If there is no matching value, NULL is returned and errno is
+ *  set to ENOENT. If the provided option value is not a hierarchical value,
+ *  NULL is also returned and errno is set to EINVAL.
+ */
+extern const tOptionValue* optionGetValue(const tOptionValue*, char const*);
+
+
+/* From: load.c line 477
+ *
+ * optionLoadLine - process a string for an option name and value
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *   pzLine       NUL-terminated text
+ *
+ *  This is a client program callable routine for setting options from, for
+ *  example, the contents of a file that they read in.  Only one option may
+ *  appear in the text.  It will be treated as a normal (non-preset) option.
+ *  
+ *  When passed a pointer to the option struct and a string, it will find
+ *  the option named by the first token on the string and set the option
+ *  argument to the remainder of the string.  The caller must NUL terminate
+ *  the string.  Any embedded new lines will be included in the option
+ *  argument.  If the input looks like one or more quoted strings, then the
+ *  input will be "cooked".  The "cooking" is identical to the string
+ *  formation used in AutoGen definition files (@pxref{basic expression}),
+ *  except that you may not use backquotes.
+ */
+extern void optionLoadLine(tOptions*, char const*);
+
+
+/* From: configfile.c line 338
+ *
+ * optionNextValue - get the next value from a hierarchical list
+ *
+ * Arguments:
+ *   pOptValue    a hierarchcal list value
+ *   pOldValue    a value from this list
+ *
+ * Returns: const tOptionValue* - a compound value structure
+ *
+ *  This routine will return the next entry after the entry passed in.  At the
+ *  end of the list, NULL will be returned.  If the entry is not found on the
+ *  list, NULL will be returned and "@var{errno}" will be set to EINVAL.
+ *  The "@var{pOldValue}" must have been gotten from a prior call to this
+ *  routine or to "@code{opitonGetValue()}".
+ */
+extern const tOptionValue* optionNextValue(const tOptionValue*, const tOptionValue*);
+
+
+/* From: usage.c line 202
+ *
+ * optionOnlyUsage - Print usage text for just the options
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *   ex_code      exit code for calling exit(3)
+ *
+ *  This routine will print only the usage for each option.
+ *  This function may be used when the emitted usage must incorporate
+ *  information not available to AutoOpts.
+ */
+extern void optionOnlyUsage(tOptions*, int);
+
+
+/* From: autoopts.c line 598
+ *
+ * optionProcess - this is the main option processing routine
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *   argc         program arg count
+ *   argv         program arg vector
+ *
+ * Returns: int - the count of the arguments processed
+ *
+ *  This is the main entry point for processing options.  It is intended
+ *  that this procedure be called once at the beginning of the execution of
+ *  a program.  Depending on options selected earlier, it is sometimes
+ *  necessary to stop and restart option processing, or to select completely
+ *  different sets of options.  This can be done easily, but you generally
+ *  do not want to do this.
+ *  
+ *  The number of arguments processed always includes the program name.
+ *  If one of the arguments is "--", then it is counted and the processing
+ *  stops.  If an error was encountered and errors are to be tolerated, then
+ *  the returned value is the index of the argument causing the error.
+ *  A hyphen by itself ("-") will also cause processing to stop and will
+ *  @emph{not} be counted among the processed arguments.  A hyphen by itself
+ *  is treated as an operand.  Encountering an operand stops option
+ *  processing.
+ */
+extern int optionProcess(tOptions*, int, char**);
+
+
+/* From: restore.c line 123
+ *
+ * optionRestore - restore option state from memory copy
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *
+ *  Copy back the option state from saved memory.
+ *  The allocated memory is left intact, so this routine can be
+ *  called repeatedly without having to call optionSaveState again.
+ *  If you are restoring a state that was saved before the first call
+ *  to optionProcess(3AO), then you may change the contents of the
+ *  argc/argv parameters to optionProcess.
+ */
+extern void optionRestore(tOptions*);
+
+
+/* From: save.c line 664
+ *
+ * optionSaveFile - saves the option state to a file
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *
+ *  This routine will save the state of option processing to a file.  The name
+ *  of that file can be specified with the argument to the @code{--save-opts}
+ *  option, or by appending the @code{rcfile} attribute to the last
+ *  @code{homerc} attribute.  If no @code{rcfile} attribute was specified, it
+ *  will default to @code{.@i{programname}rc}.  If you wish to specify another
+ *  file, you should invoke the @code{SET_OPT_SAVE_OPTS(@i{filename})} macro.
+ *  
+ *  The recommend usage is as follows:
+ *  @example
+ *  optionProcess(&progOptions, argc, argv);
+ *  if (i_want_a_non_standard_place_for_this)
+ *  SET_OPT_SAVE_OPTS("myfilename");
+ *  optionSaveFile(&progOptions);
+ *  @end example
+ */
+extern void optionSaveFile(tOptions*);
+
+
+/* From: restore.c line 71
+ *
+ * optionSaveState - saves the option state to memory
+ *
+ * Arguments:
+ *   pOpts        program options descriptor
+ *
+ *  This routine will allocate enough memory to save the current option
+ *  processing state.  If this routine has been called before, that memory
+ *  will be reused.  You may only save one copy of the option state.  This
+ *  routine may be called before optionProcess(3AO).  If you do call it
+ *  before the first call to optionProcess, then you may also change the
+ *  contents of argc/argv after you call optionRestore(3AO)
+ *  
+ *  In fact, more strongly put: it is safest to only use this function
+ *  before having processed any options.  In particular, the saving and
+ *  restoring of stacked string arguments and hierarchical values is
+ *  disabled.  The values are not saved.
+ */
+extern void optionSaveState(tOptions*);
+
+
+/* From: nested.c line 551
+ *
+ * optionUnloadNested - Deallocate the memory for a nested value
+ *
+ * Arguments:
+ *   pOptVal      the hierarchical value
+ *
+ *  A nested value needs to be deallocated.  The pointer passed in should
+ *  have been gotten from a call to @code{configFileLoad()} (See
+ *  @pxref{libopts-configFileLoad}).
+ */
+extern void optionUnloadNested(tOptionValue const *);
+
+
+/* From: version.c line 31
+ *
+ * optionVersion - return the compiled AutoOpts version number
+ *
+ * Returns: char const* - the version string in constant memory
+ *
+ *  Returns the full version string compiled into the library.
+ *  The returned string cannot be modified.
+ */
+extern char const* optionVersion(void);
+
+
+/* From: ../compat/pathfind.c line 29
+ *
+ * pathfind - fild a file in a list of directories
+ *
+ * Arguments:
+ *   path         colon separated list of search directories
+ *   file         the name of the file to look for
+ *   mode         the mode bits that must be set to match
+ *
+ * Returns: char* - the path to the located file
+ *
+ * the pathfind function is available only if HAVE_PATHFIND is not defined
+ *
+ *  pathfind looks for a a file with name "FILE" and "MODE" access
+ *  along colon delimited "PATH", and returns the full pathname as a
+ *  string, or NULL if not found.  If "FILE" contains a slash, then
+ *  it is treated as a relative or absolute path and "PATH" is ignored.
+ *  
+ *  @strong{NOTE}: this function is compiled into @file{libopts} only if
+ *  it is not natively supplied.
+ *  
+ *  The "MODE" argument is a string of option letters chosen from the
+ *  list below:
+ *  @example
+ *  Letter    Meaning
+ *  r         readable
+ *  w         writable
+ *  x         executable
+ *  f         normal file       (NOT IMPLEMENTED)
+ *  b         block special     (NOT IMPLEMENTED)
+ *  c         character special (NOT IMPLEMENTED)
+ *  d         directory         (NOT IMPLEMENTED)
+ *  p         FIFO (pipe)       (NOT IMPLEMENTED)
+ *  u         set user ID bit   (NOT IMPLEMENTED)
+ *  g         set group ID bit  (NOT IMPLEMENTED)
+ *  k         sticky bit        (NOT IMPLEMENTED)
+ *  s         size nonzero      (NOT IMPLEMENTED)
+ *  @end example
+ */
+#ifndef HAVE_PATHFIND
+extern char* pathfind(char const*, char const*, char const*);
+#endif /* HAVE_PATHFIND */
+
+
+/* From: streqvcmp.c line 209
+ *
+ * strequate - map a list of characters to the same value
+ *
+ * Arguments:
+ *   ch_list      characters to equivalence
+ *
+ *  Each character in the input string get mapped to the first character
+ *  in the string.
+ *  This function name is mapped to option_strequate so as to not conflict
+ *  with the POSIX name space.
+ */
+extern void strequate(char const*);
+
+
+/* From: streqvcmp.c line 119
+ *
+ * streqvcmp - compare two strings with an equivalence mapping
+ *
+ * Arguments:
+ *   str1         first string
+ *   str2         second string
+ *
+ * Returns: int - the difference between two differing characters
+ *
+ *  Using a character mapping, two strings are compared for "equivalence".
+ *  Each input character is mapped to a comparison character and the
+ *  mapped-to characters are compared for the two NUL terminated input strings.
+ *  This function name is mapped to option_streqvcmp so as to not conflict
+ *  with the POSIX name space.
+ */
+extern int streqvcmp(char const*, char const*);
+
+
+/* From: streqvcmp.c line 156
+ *
+ * streqvmap - Set the character mappings for the streqv functions
+ *
+ * Arguments:
+ *   From         Input character
+ *   To           Mapped-to character
+ *   ct           compare length
+ *
+ *  Set the character mapping.  If the count (@code{ct}) is set to zero, then
+ *  the map is cleared by setting all entries in the map to their index
+ *  value.  Otherwise, the "@code{From}" character is mapped to the "@code{To}"
+ *  character.  If @code{ct} is greater than 1, then @code{From} and @code{To}
+ *  are incremented and the process repeated until @code{ct} entries have been
+ *  set. For example,
+ *  @example
+ *  streqvmap('a', 'A', 26);
+ *  @end example
+ *  @noindent
+ *  will alter the mapping so that all English lower case letters
+ *  will map to upper case.
+ *  
+ *  This function name is mapped to option_streqvmap so as to not conflict
+ *  with the POSIX name space.
+ */
+extern void streqvmap(char, char, int);
+
+
+/* From: streqvcmp.c line 78
+ *
+ * strneqvcmp - compare two strings with an equivalence mapping
+ *
+ * Arguments:
+ *   str1         first string
+ *   str2         second string
+ *   ct           compare length
+ *
+ * Returns: int - the difference between two differing characters
+ *
+ *  Using a character mapping, two strings are compared for "equivalence".
+ *  Each input character is mapped to a comparison character and the
+ *  mapped-to characters are compared for the two NUL terminated input strings.
+ *  The comparison is limited to @code{ct} bytes.
+ *  This function name is mapped to option_strneqvcmp so as to not conflict
+ *  with the POSIX name space.
+ */
+extern int strneqvcmp(char const*, char const*, int);
+
+
+/* From: streqvcmp.c line 235
+ *
+ * strtransform - convert a string into its mapped-to value
+ *
+ * Arguments:
+ *   dest         output string
+ *   src          input string
+ *
+ *  Each character in the input string is mapped and the mapped-to
+ *  character is put into the output.
+ *  This function name is mapped to option_strtransform so as to not conflict
+ *  with the POSIX name space.
+ *  
+ *  The source and destination may be the same.
+ */
+extern void strtransform(char*, char const*);
+
+/*  AutoOpts PRIVATE FUNCTIONS:  */
+tOptProc optionStackArg, optionUnstackArg, optionBooleanVal, optionNumericVal;
+
+extern char* ao_string_cook(char*, int*);
+
+extern unsigned int ao_string_cook_escape_char(char const*, char*, unsigned int);
+
+extern void genshelloptUsage(tOptions*, int);
+
+extern void optionBooleanVal(tOptions*, tOptDesc*);
+
+extern uintptr_t optionEnumerationVal(tOptions*, tOptDesc*, char const * const *, unsigned int);
+
+extern void optionFileCheck(tOptions*, tOptDesc*, teOptFileType, tuFileMode);
+
+extern char const * optionKeywordName(tOptDesc*, unsigned int);
+
+extern void optionLoadOpt(tOptions*, tOptDesc*);
+
+extern ag_bool optionMakePath(char*, int, char const*, char const*);
+
+extern void optionNestedVal(tOptions*, tOptDesc*);
+
+extern void optionNumericVal(tOptions*, tOptDesc*);
+
+extern void optionPagedUsage(tOptions*, tOptDesc*);
+
+extern void optionParseShell(tOptions*);
+
+extern void optionPrintVersion(tOptions*, tOptDesc*);
+
+extern void optionPutShell(tOptions*);
+
+extern void optionResetOpt(tOptions*, tOptDesc*);
+
+extern void optionSetMembers(tOptions*, tOptDesc*, char const * const *, unsigned int);
+
+extern void optionShowRange(tOptions*, tOptDesc*, void *, int);
+
+extern void optionStackArg(tOptions*, tOptDesc*);
+
+extern void optionTimeDate(tOptions*, tOptDesc*);
+
+extern void optionTimeVal(tOptions*, tOptDesc*);
+
+extern void optionUnstackArg(tOptions*, tOptDesc*);
+
+extern void optionUsage(tOptions*, int);
+
+extern void optionVendorOption(tOptions *, tOptDesc *);
+
+extern void optionVersionStderr(tOptions*, tOptDesc*);
+
+extern void* text_mmap(char const*, int, int, tmap_info_t*);
+
+extern int text_munmap(tmap_info_t*);
+
+CPLUSPLUS_CLOSER
+#endif /* AUTOOPTS_OPTIONS_H_GUARD */
+/*
+ * Local Variables:
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * options.h ends here */
diff --git a/libopts/autoopts/project.h b/libopts/autoopts/project.h
new file mode 100644 (file)
index 0000000..b01affb
--- /dev/null
@@ -0,0 +1,50 @@
+
+#ifndef AUTOGEN_PROJECT_H
+#define AUTOGEN_PROJECT_H
+
+#include "config.h"
+
+/*
+ *  Procedure success codes
+ *
+ *  USAGE:  define procedures to return "tSuccess".  Test their results
+ *          with the SUCCEEDED, FAILED and HADGLITCH macros.
+ *
+ *  Microsoft sticks its nose into user space here, so for Windows' sake,
+ *  make sure all of these are undefined.
+ */
+#undef  SUCCESS
+#undef  FAILURE
+#undef  PROBLEM
+#undef  SUCCEEDED
+#undef  SUCCESSFUL
+#undef  FAILED
+#undef  HADGLITCH
+
+#define SUCCESS  ((tSuccess) 0)
+#define FAILURE  ((tSuccess)-1)
+#define PROBLEM  ((tSuccess) 1)
+
+typedef int tSuccess;
+
+#define SUCCEEDED(p)    ((p) == SUCCESS)
+#define SUCCESSFUL(p)   SUCCEEDED(p)
+#define FAILED(p)       ((p) <  SUCCESS)
+#define HADGLITCH(p)    ((p) >  SUCCESS)
+
+#ifndef STR
+#  define __STR(s)      #s
+#  define STR(s)        __STR(s)
+#endif
+
+#define STRSIZE(s)      (sizeof(s)-1)
+
+#ifdef DEFINING
+#  define VALUE(s)      = s
+#  define MODE
+#else
+#  define VALUE(s)
+#  define MODE extern
+#endif
+
+#endif /* AUTOGEN_PROJECT_H */
diff --git a/libopts/autoopts/usage-txt.h b/libopts/autoopts/usage-txt.h
new file mode 100644 (file)
index 0000000..20492a4
--- /dev/null
@@ -0,0 +1,433 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (usage-txt.h)
+ *  
+ *  It has been AutoGen-ed  December 29, 2011 at 12:02:34 PM by AutoGen 5.14
+ *  From the definitions    usage-txt.def
+ *  and the template file   usage-txt.tpl
+ *
+ *  This file handles all the bookkeeping required for tracking all the little
+ *  tiny strings used by the AutoOpts library.  There are 145
+ *  of them.  This is not versioned because it is entirely internal to the
+ *  library and accessed by client code only in a very well-controlled way:
+ *  they may substitute translated strings using a procedure that steps through
+ *  all the string pointers.
+ *
+ *  Copyright (C) 1992-2011 Bruce Korb, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU Lesser General Public License, version 3 or later
+ *     <http://gnu.org/licenses/lgpl.html>
+ *
+ *  AutoOpts is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU Lesser General Public License as published
+ *  by the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  AutoOpts is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU Lesser General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.";
+ */
+#ifndef AUTOOPTS_USAGE_TXT_H_GUARD
+#define AUTOOPTS_USAGE_TXT_H_GUARD 1
+
+#undef  cch_t
+#define cch_t char const
+
+/*
+ *  One structure to hold all the pointers to all the stringlets.
+ */
+typedef struct {
+  int       field_ct;
+  char*     utpz_GnuBoolArg;
+  char*     utpz_GnuKeyArg;
+  char*     utpz_GnuFileArg;
+  char*     utpz_GnuKeyLArg;
+  char*     utpz_GnuTimeArg;
+  char*     utpz_GnuNumArg;
+  char*     utpz_GnuStrArg;
+  cch_t*    apz_str[ 138 ];
+} usage_text_t;
+
+/*
+ *  Declare the global structure with all the pointers to translated
+ *  strings.  This is then used by the usage generation procedure.
+ */
+extern usage_text_t option_usage_text;
+
+#if defined(AUTOOPTS_INTERNAL) /* DEFINE ALL THE STRINGS = = = = = */
+/*
+ *  Provide a mapping from a short name to fields in this structure.
+ */
+#define zAO_Alloc             (option_usage_text.apz_str[  0])
+#define zAO_Bad               (option_usage_text.apz_str[  1])
+#define zAO_Big               (option_usage_text.apz_str[  2])
+#define zAO_Err               (option_usage_text.apz_str[  3])
+#define zAO_Realloc           (option_usage_text.apz_str[  4])
+#define zAO_Sml               (option_usage_text.apz_str[  5])
+#define zAO_Strdup            (option_usage_text.apz_str[  6])
+#define zAO_Ver               (option_usage_text.apz_str[  7])
+#define zAO_Woops             (option_usage_text.apz_str[  8])
+#define zAliasRange           (option_usage_text.apz_str[  9])
+#define zAll                  (option_usage_text.apz_str[ 10])
+#define zAlt                  (option_usage_text.apz_str[ 11])
+#define zAmbigKey             (option_usage_text.apz_str[ 12])
+#define zAmbigList            (option_usage_text.apz_str[ 13])
+#define zAmbigOptStr          (option_usage_text.apz_str[ 14])
+#define zAmbiguous            (option_usage_text.apz_str[ 15])
+#define zArgsMust             (option_usage_text.apz_str[ 16])
+#define zAtMost               (option_usage_text.apz_str[ 17])
+#define zAuto                 (option_usage_text.apz_str[ 18])
+#define zBadPipe              (option_usage_text.apz_str[ 19])
+#define zBadVerArg            (option_usage_text.apz_str[ 20])
+#define zCantFmt              (option_usage_text.apz_str[ 21])
+#define zCantSave             (option_usage_text.apz_str[ 22])
+#define zCfgAO_Flags          (option_usage_text.apz_str[ 23])
+#define zCfgProg              (option_usage_text.apz_str[ 24])
+#define zDefaultOpt           (option_usage_text.apz_str[ 25])
+#define zDis                  (option_usage_text.apz_str[ 26])
+#define zDisabledErr          (option_usage_text.apz_str[ 27])
+#define zDisabledOpt          (option_usage_text.apz_str[ 28])
+#define zDisabledWhy          (option_usage_text.apz_str[ 29])
+#define zEnab                 (option_usage_text.apz_str[ 30])
+#define zEquiv                (option_usage_text.apz_str[ 31])
+#define zErrOnly              (option_usage_text.apz_str[ 32])
+#define zExamineFmt           (option_usage_text.apz_str[ 33])
+#define zFiveSpaces           (option_usage_text.apz_str[ 34])
+#define zFlagOkay             (option_usage_text.apz_str[ 35])
+#define zFmtFmt               (option_usage_text.apz_str[ 36])
+#define zForkFail             (option_usage_text.apz_str[ 37])
+#define zFreopenFail          (option_usage_text.apz_str[ 38])
+#define zFSErrOptLoad         (option_usage_text.apz_str[ 39])
+#define zFSErrReadFile        (option_usage_text.apz_str[ 40])
+#define zFSOptError           (option_usage_text.apz_str[ 41])
+#define zFSOptErrMayExist     (option_usage_text.apz_str[ 42])
+#define zFSOptErrMustExist    (option_usage_text.apz_str[ 43])
+#define zFSOptErrNoExist      (option_usage_text.apz_str[ 44])
+#define zFSOptErrOpen         (option_usage_text.apz_str[ 45])
+#define zFSOptErrFopen        (option_usage_text.apz_str[ 46])
+#define zFileCannotExist      (option_usage_text.apz_str[ 47])
+#define zFileMustExist        (option_usage_text.apz_str[ 48])
+#define zGenshell             (option_usage_text.apz_str[ 49])
+#define zGnuBoolArg           (option_usage_text.utpz_GnuBoolArg)
+#define zGnuBreak             (option_usage_text.apz_str[ 50])
+#define zGnuKeyArg            (option_usage_text.utpz_GnuKeyArg)
+#define zGnuFileArg           (option_usage_text.utpz_GnuFileArg)
+#define zGnuKeyLArg           (option_usage_text.utpz_GnuKeyLArg)
+#define zGnuTimeArg           (option_usage_text.utpz_GnuTimeArg)
+#define zGnuNestArg           (option_usage_text.apz_str[ 51])
+#define zGnuNumArg            (option_usage_text.utpz_GnuNumArg)
+#define zGnuOptArg            (option_usage_text.apz_str[ 52])
+#define zGnuOptFmt            (option_usage_text.apz_str[ 53])
+#define zGnuStrArg            (option_usage_text.utpz_GnuStrArg)
+#define zIllOptChr            (option_usage_text.apz_str[ 54])
+#define zIllOptStr            (option_usage_text.apz_str[ 55])
+#define zIllVendOptStr        (option_usage_text.apz_str[ 56])
+#define zIntRange             (option_usage_text.apz_str[ 57])
+#define zInvalOptDesc         (option_usage_text.apz_str[ 58])
+#define zLowerBits            (option_usage_text.apz_str[ 59])
+#define zMembers              (option_usage_text.apz_str[ 60])
+#define zMisArg               (option_usage_text.apz_str[ 61])
+#define zMultiEquiv           (option_usage_text.apz_str[ 62])
+#define zMust                 (option_usage_text.apz_str[ 63])
+#define zNeedOne              (option_usage_text.apz_str[ 64])
+#define zNoArg                (option_usage_text.apz_str[ 65])
+#define zNoArgv               (option_usage_text.apz_str[ 66])
+#define zNoArgs               (option_usage_text.apz_str[ 67])
+#define zNoCreat              (option_usage_text.apz_str[ 68])
+#define zNoFlags              (option_usage_text.apz_str[ 69])
+#define zNoKey                (option_usage_text.apz_str[ 70])
+#define zNoLim                (option_usage_text.apz_str[ 71])
+#define zNoPreset             (option_usage_text.apz_str[ 72])
+#define zNoResetArg           (option_usage_text.apz_str[ 73])
+#define zNoRq_NoShrtTtl       (option_usage_text.apz_str[ 74])
+#define zNoRq_ShrtTtl         (option_usage_text.apz_str[ 75])
+#define zNoStat               (option_usage_text.apz_str[ 76])
+#define zNoState              (option_usage_text.apz_str[ 77])
+#define zNone                 (option_usage_text.apz_str[ 78])
+#define zNotDef               (option_usage_text.apz_str[ 79])
+#define zNotCmdOpt            (option_usage_text.apz_str[ 80])
+#define zNotEnough            (option_usage_text.apz_str[ 81])
+#define zNotFile              (option_usage_text.apz_str[ 82])
+#define zNotNumber            (option_usage_text.apz_str[ 83])
+#define zNotDate              (option_usage_text.apz_str[ 84])
+#define zNotDuration          (option_usage_text.apz_str[ 85])
+#define zNrmOptFmt            (option_usage_text.apz_str[ 86])
+#define zNumberOpt            (option_usage_text.apz_str[ 87])
+#define zOnlyOne              (option_usage_text.apz_str[ 88])
+#define zOptsOnly             (option_usage_text.apz_str[ 89])
+#define zOutputFail           (option_usage_text.apz_str[ 90])
+#define zPathFmt              (option_usage_text.apz_str[ 91])
+#define zPlsSendBugs          (option_usage_text.apz_str[ 92])
+#define zPreset               (option_usage_text.apz_str[ 93])
+#define zPresetFile           (option_usage_text.apz_str[ 94])
+#define zPresetIntro          (option_usage_text.apz_str[ 95])
+#define zProhib               (option_usage_text.apz_str[ 96])
+#define zReorder              (option_usage_text.apz_str[ 97])
+#define zRange                (option_usage_text.apz_str[ 98])
+#define zRangeAbove           (option_usage_text.apz_str[ 99])
+#define zRangeLie             (option_usage_text.apz_str[100])
+#define zRangeOnly            (option_usage_text.apz_str[101])
+#define zRangeOr              (option_usage_text.apz_str[102])
+#define zRangeErr             (option_usage_text.apz_str[103])
+#define zRangeExact           (option_usage_text.apz_str[104])
+#define zRangeScaled          (option_usage_text.apz_str[105])
+#define zRangeUpto            (option_usage_text.apz_str[106])
+#define zResetNotConfig       (option_usage_text.apz_str[107])
+#define zReqFmt               (option_usage_text.apz_str[108])
+#define zReqOptFmt            (option_usage_text.apz_str[109])
+#define zReqThese             (option_usage_text.apz_str[110])
+#define zReq_NoShrtTtl        (option_usage_text.apz_str[111])
+#define zReq_ShrtTtl          (option_usage_text.apz_str[112])
+#define zSepChars             (option_usage_text.apz_str[113])
+#define zSetMemberSettings    (option_usage_text.apz_str[114])
+#define zShrtGnuOptFmt        (option_usage_text.apz_str[115])
+#define zSixSpaces            (option_usage_text.apz_str[116])
+#define zStdBoolArg           (option_usage_text.apz_str[117])
+#define zStdBreak             (option_usage_text.apz_str[118])
+#define zStdFileArg           (option_usage_text.apz_str[119])
+#define zStdKeyArg            (option_usage_text.apz_str[120])
+#define zStdKeyLArg           (option_usage_text.apz_str[121])
+#define zStdTimeArg           (option_usage_text.apz_str[122])
+#define zStdNestArg           (option_usage_text.apz_str[123])
+#define zStdNoArg             (option_usage_text.apz_str[124])
+#define zStdNumArg            (option_usage_text.apz_str[125])
+#define zStdOptArg            (option_usage_text.apz_str[126])
+#define zStdReqArg            (option_usage_text.apz_str[127])
+#define zStdStrArg            (option_usage_text.apz_str[128])
+#define zTabHyp               (option_usage_text.apz_str[129])
+#define zTabHypAnd            (option_usage_text.apz_str[130])
+#define zTabout               (option_usage_text.apz_str[131])
+#define zThreeSpaces          (option_usage_text.apz_str[132])
+#define zTwoSpaces            (option_usage_text.apz_str[133])
+#define zUpTo                 (option_usage_text.apz_str[134])
+#define zValidKeys            (option_usage_text.apz_str[135])
+#define zVendOptsAre          (option_usage_text.apz_str[136])
+#define zVendIntro            (option_usage_text.apz_str[137])
+
+  /*
+   *  First, set up the strings.  Some of these are writable.  These are all in
+   *  English.  This gets compiled into libopts and is distributed here so that
+   *  xgettext (or equivalents) can extract these strings for translation.
+   */
+
+  static char    eng_zGnuBoolArg[] = "=T/F";
+  static char    eng_zGnuKeyArg[] = "=KWd";
+  static char    eng_zGnuFileArg[] = "=file";
+  static char    eng_zGnuKeyLArg[] = "=Mbr";
+  static char    eng_zGnuTimeArg[] = "=Tim";
+  static char    eng_zGnuNumArg[] = "=num";
+  static char    eng_zGnuStrArg[] = "=str";
+static char const usage_txt[4619] =
+/*     0 */ "malloc of %d bytes failed\n\0"
+/*    27 */ "AutoOpts function called without option descriptor\n\0"
+/*    79 */ "\tThis exceeds the compiled library version:  \0"
+/*   125 */ "Automated Options Processing Error!\n"
+            "\t%s called AutoOpts function with structure version %d:%d:%d.\n\0"
+/*   224 */ "realloc of %d bytes at 0x%p failed\n\0"
+/*   260 */ "\tThis is less than the minimum library version:  \0"
+/*   310 */ "strdup of %d byte string failed\n\0"
+/*   343 */ "Automated Options version %s\n"
+            "\tcopyright (c) 1999-2011 by Bruce Korb - all rights reserved\n\0"
+/*   434 */ "AutoOpts lib error: defaulted to option with optional arg\n\0"
+/*   493 */ "(AutoOpts bug):  Aliasing option is out of range.\0"
+/*   543 */ "all\0"
+/*   547 */ "\t\t\t\t- an alternate for %s\n\0"
+/*   574 */ "%s error:  the keyword `%s' is ambiguous for %s\n\0"
+/*   623 */ "  The following options match:\n\0"
+/*   655 */ "%s: ambiguous option name: %s (matches %d options)\n\0"
+/*   707 */ "  %s%s\n\0"
+/*   715 */ "%s: Command line arguments required\n\0"
+/*   752 */ "%d %s%s options allowed\n\0"
+/*   777 */ "version and help options:\0"
+/*   803 */ "Error %d (%s) from the pipe(2) syscall\n\0"
+/*   843 */ "ERROR: version option argument '%c' invalid.  Use:\n"
+            "\t'v' - version only\n"
+            "\t'c' - version and copyright\n"
+            "\t'n' - version and copyright notice\n\0"
+/*   980 */ "ERROR:  %s option conflicts with the %s option\n\0"
+/*  1028 */ "%s(optionSaveState): error: cannot allocate %d bytes\n\0"
+/*  1082 */ "auto-options\0"
+/*  1095 */ "program\0"
+/*  1103 */ "\t\t\t\t- default option for unnamed options\n\0"
+/*  1145 */ "\t\t\t\t- disabled as --%s\n\0"
+/*  1169 */ "%s: The ``%s'' option has been disabled\0"
+/*  1209 */ " --- %-14s %s\n\0"
+/*  1224 */ "This option has been disabled\0"
+/*  1254 */ "\t\t\t\t- enabled by default\n\0"
+/*  1280 */ "-equivalence\0"
+/*  1293 */ "ERROR:  only \0"
+/*  1307 */ " - examining environment variables named %s_*\n\0"
+/*  1354 */ "     \0"
+/*  1360 */ "Options are specified by doubled hyphens and their name or by a single\n"
+            "hyphen and the flag character.\n\0"
+/*  1463 */ "%%-%ds %%s\n\0"
+/*  1475 */ "fs error %d (%s) on fork - cannot obtain %s usage\n\0"
+/*  1526 */ "fs error %d (%s) on freopen\n\0"
+/*  1555 */ "File error %d (%s) opening %s for loading options\n\0"
+/*  1606 */ "fs error %d (%s) reading file %s\n\0"
+/*  1640 */ "fs error %d (%s) on %s %s for option %s\n\0"
+/*  1681 */ "stat-ing for directory\0"
+/*  1704 */ "stat-ing for regular file\0"
+/*  1730 */ "stat-ing for non-existant file\0"
+/*  1761 */ "open-ing file\0"
+/*  1775 */ "fopen-ing file\0"
+/*  1790 */ "\t\t\t\t- file must not pre-exist\n\0"
+/*  1821 */ "\t\t\t\t- file must pre-exist\n\0"
+/*  1848 */ "\n"
+            "= = = = = = = =\n\n"
+            "This incarnation of genshell will produce\n"
+            "a shell script to parse the options for %s:\n\n\0"
+/*  1954 */ "\n"
+            "%s\n\n\0"
+/*  1960 */ "=Cplx\0"
+/*  1966 */ "[=arg]\0"
+/*  1973 */ "--%2$s%1$s\0"
+/*  1984 */ "%s: illegal option -- %c\n\0"
+/*  2010 */ "%s: illegal option -- %s\n\0"
+/*  2036 */ "%s: unknown vendor extension option -- %s\n\0"
+/*  2079 */ "  or an integer from %d through %d\n\0"
+/*  2115 */ "AutoOpts ERROR:  invalid option descriptor for %s\n\0"
+/*  2166 */ "  or an integer mask with any of the lower %d bits set\n\0"
+/*  2222 */ "\t\t\t\t- is a set membership option\n\0"
+/*  2256 */ "%s: option `%s' requires an argument\n\0"
+/*  2294 */ "Equivalenced option '%s' was equivalenced to both\n"
+            "\t'%s' and '%s'\0"
+/*  2359 */ "\t\t\t\t- must appear between %d and %d times\n\0"
+/*  2402 */ "ERROR:  The %s option is required\n\0"
+/*  2437 */ "%s: option `%s' cannot have an argument\n\0"
+/*  2478 */ "%s: cannot allocate new argument vector\n\0"
+/*  2519 */ "%s: Command line arguments not allowed\n\0"
+/*  2559 */ "error %d (%s) creating %s\n\0"
+/*  2586 */ "Options are specified by single or double hyphens and their name.\n\0"
+/*  2653 */ "%s error:  `%s' does not match any %s keywords\n\0"
+/*  2701 */ "\t\t\t\t- may appear multiple times\n\0"
+/*  2734 */ "\t\t\t\t- may not be preset\n\0"
+/*  2759 */ "The 'reset-option' option requires an argument\n\0"
+/*  2807 */ "   Arg Option-Name    Description\n\0"
+/*  2842 */ "  Flg Arg Option-Name    Description\n\0"
+/*  2880 */ "error %d (%s) stat-ing %s\n\0"
+/*  2907 */ "%s(optionRestore): error: no saved option state\n\0"
+/*  2956 */ "none\0"
+/*  2961 */ "'%s' not defined\n\0"
+/*  2979 */ "'%s' is not a command line option\n\0"
+/*  3014 */ "ERROR:  The %s option must appear %d times\n\0"
+/*  3058 */ "error:  cannot load options from non-regular file %s\n\0"
+/*  3112 */ "%s error:  `%s' is not a recognizable number\n\0"
+/*  3158 */ "%s error:  `%s' is not a recognizable date/time\n\0"
+/*  3207 */ "%s error:  `%s' is not a recognizable time duration\n\0"
+/*  3260 */ " %3s %s\0"
+/*  3268 */ "The '-#<number>' option may omit the hash char\n\0"
+/*  3316 */ "one %s%s option allowed\n\0"
+/*  3341 */ "All arguments are named options.\n\0"
+/*  3375 */ "Write failure to output file\0"
+/*  3404 */ " - reading file %s\0"
+/*  3423 */ "\n"
+            "please send bug reports to:  %s\n\0"
+/*  3457 */ "\t\t\t\t- may NOT appear - preset only\n\0"
+/*  3493 */ "#  preset/initialization file\n"
+            "#  %s#\n\0"
+/*  3531 */ "\n"
+            "The following option preset mechanisms are supported:\n\0"
+/*  3587 */ "prohibits these options:\n\0"
+/*  3613 */ "Operands and options may be intermixed.  They will be reordered.\n\0"
+/*  3679 */ "%s%ld to %ld\0"
+/*  3692 */ "%sgreater than or equal to %ld\0"
+/*  3723 */ "%sIt must lie in one of the ranges:\n\0"
+/*  3760 */ "%sIt must be in the range:\n\0"
+/*  3788 */ ", or\n\0"
+/*  3794 */ "%s error:  %s option value ``%s'' is out of range.\n\0"
+/*  3846 */ "%s%ld exactly\0"
+/*  3860 */ "%sis scalable with a suffix: k/K/m/M/g/G/t/T\n\0"
+/*  3906 */ "%sless than or equal to %ld\0"
+/*  3934 */ "The --reset-option has not been configured.\n\0"
+/*  3979 */ "ERROR:  %s option requires the %s option\n\0"
+/*  4021 */ " %3s %-14s %s\0"
+/*  4035 */ "requires these options:\n\0"
+/*  4060 */ "   Arg Option-Name   Req?  Description\n\0"
+/*  4100 */ "  Flg Arg Option-Name   Req?  Description\n\0"
+/*  4143 */ "-_^\0"
+/*  4147 */ "or you may use a numeric representation.  Preceding these with a '!' will\n"
+            "clear the bits, specifying 'none' will clear all bits, and 'all' will set them\n"
+            "all.  Multiple entries may be passed as an option argument list.\n\0"
+/*  4366 */ "%s\0"
+/*  4369 */ "      \0"
+/*  4376 */ "T/F\0"
+/*  4380 */ "\n"
+            "%s\n\n"
+            "%s\0"
+/*  4388 */ "Fil\0"
+/*  4392 */ "KWd\0"
+/*  4396 */ "Mbr\0"
+/*  4400 */ "Tim\0"
+/*  4404 */ "Cpx\0"
+/*  4408 */ "no \0"
+/*  4412 */ "Num\0"
+/*  4416 */ "opt\0"
+/*  4420 */ "YES\0"
+/*  4424 */ "Str\0"
+/*  4428 */ "\t\t\t\t- \0"
+/*  4435 */ "\t\t\t\t-- and \0"
+/*  4447 */ "\t\t\t\t%s\n\0"
+/*  4455 */ "   \0"
+/*  4459 */ "  \0"
+/*  4462 */ "\t\t\t\t- may appear up to %d times\n\0"
+/*  4495 */ "The valid \"%s\" option keywords are:\n\0"
+/*  4532 */ "These additional options are:\0"
+/*  4562 */ "The next option supports vendor supported extra options:";
+
+
+  /*
+   *  Now, define (and initialize) the structure that contains
+   *  the pointers to all these strings.
+   *  Aren't you glad you don't maintain this by hand?
+   */
+  usage_text_t option_usage_text = {
+    145,
+    eng_zGnuBoolArg, eng_zGnuKeyArg,  eng_zGnuFileArg, eng_zGnuKeyLArg,
+    eng_zGnuTimeArg, eng_zGnuNumArg,  eng_zGnuStrArg,
+    {
+      usage_txt +   0, usage_txt +  27, usage_txt +  79, usage_txt + 125,
+      usage_txt + 224, usage_txt + 260, usage_txt + 310, usage_txt + 343,
+      usage_txt + 434, usage_txt + 493, usage_txt + 543, usage_txt + 547,
+      usage_txt + 574, usage_txt + 623, usage_txt + 655, usage_txt + 707,
+      usage_txt + 715, usage_txt + 752, usage_txt + 777, usage_txt + 803,
+      usage_txt + 843, usage_txt + 980, usage_txt +1028, usage_txt +1082,
+      usage_txt +1095, usage_txt +1103, usage_txt +1145, usage_txt +1169,
+      usage_txt +1209, usage_txt +1224, usage_txt +1254, usage_txt +1280,
+      usage_txt +1293, usage_txt +1307, usage_txt +1354, usage_txt +1360,
+      usage_txt +1463, usage_txt +1475, usage_txt +1526, usage_txt +1555,
+      usage_txt +1606, usage_txt +1640, usage_txt +1681, usage_txt +1704,
+      usage_txt +1730, usage_txt +1761, usage_txt +1775, usage_txt +1790,
+      usage_txt +1821, usage_txt +1848, usage_txt +1954, usage_txt +1960,
+      usage_txt +1966, usage_txt +1973, usage_txt +1984, usage_txt +2010,
+      usage_txt +2036, usage_txt +2079, usage_txt +2115, usage_txt +2166,
+      usage_txt +2222, usage_txt +2256, usage_txt +2294, usage_txt +2359,
+      usage_txt +2402, usage_txt +2437, usage_txt +2478, usage_txt +2519,
+      usage_txt +2559, usage_txt +2586, usage_txt +2653, usage_txt +2701,
+      usage_txt +2734, usage_txt +2759, usage_txt +2807, usage_txt +2842,
+      usage_txt +2880, usage_txt +2907, usage_txt +2956, usage_txt +2961,
+      usage_txt +2979, usage_txt +3014, usage_txt +3058, usage_txt +3112,
+      usage_txt +3158, usage_txt +3207, usage_txt +3260, usage_txt +3268,
+      usage_txt +3316, usage_txt +3341, usage_txt +3375, usage_txt +3404,
+      usage_txt +3423, usage_txt +3457, usage_txt +3493, usage_txt +3531,
+      usage_txt +3587, usage_txt +3613, usage_txt +3679, usage_txt +3692,
+      usage_txt +3723, usage_txt +3760, usage_txt +3788, usage_txt +3794,
+      usage_txt +3846, usage_txt +3860, usage_txt +3906, usage_txt +3934,
+      usage_txt +3979, usage_txt +4021, usage_txt +4035, usage_txt +4060,
+      usage_txt +4100, usage_txt +4143, usage_txt +4147, usage_txt +4366,
+      usage_txt +4369, usage_txt +4376, usage_txt +4380, usage_txt +4388,
+      usage_txt +4392, usage_txt +4396, usage_txt +4400, usage_txt +4404,
+      usage_txt +4408, usage_txt +4412, usage_txt +4416, usage_txt +4420,
+      usage_txt +4424, usage_txt +4428, usage_txt +4435, usage_txt +4447,
+      usage_txt +4455, usage_txt +4459, usage_txt +4462, usage_txt +4495,
+      usage_txt +4532, usage_txt +4562
+    }
+  };
+
+#endif /* DO_TRANSLATIONS */
+#endif /* AUTOOPTS_USAGE_TXT_H_GUARD */
diff --git a/libopts/boolean.c b/libopts/boolean.c
new file mode 100644 (file)
index 0000000..8079231
--- /dev/null
@@ -0,0 +1,92 @@
+
+/**
+ * \file boolean.c
+ *
+ * Time-stamp:      "2010-07-10 11:02:10 bkorb"
+ *
+ *   Automated Options Paged Usage module.
+ *
+ *  This routine will run run-on options through a pager so the
+ *  user may examine, print or edit them at their leisure.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*=export_func  optionBooleanVal
+ * private:
+ *
+ * what:  Decipher a boolean value
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Decipher a true or false value for a boolean valued option argument.
+ *  The value is true, unless it starts with 'n' or 'f' or "#f" or
+ *  it is an empty string or it is a number that evaluates to zero.
+=*/
+void
+optionBooleanVal( tOptions* pOpts, tOptDesc* pOD )
+{
+    char* pz;
+    ag_bool  res = AG_TRUE;
+
+    if ((pOD->fOptState & OPTST_RESET) != 0)
+        return;
+
+    if (pOD->optArg.argString == NULL) {
+        pOD->optArg.argBool = AG_FALSE;
+        return;
+    }
+
+    switch (*(pOD->optArg.argString)) {
+    case '0':
+    {
+        long  val = strtol( pOD->optArg.argString, &pz, 0 );
+        if ((val != 0) || (*pz != NUL))
+            break;
+        /* FALLTHROUGH */
+    }
+    case 'N':
+    case 'n':
+    case 'F':
+    case 'f':
+    case NUL:
+        res = AG_FALSE;
+        break;
+    case '#':
+        if (pOD->optArg.argString[1] != 'f')
+            break;
+        res = AG_FALSE;
+    }
+
+    if (pOD->fOptState & OPTST_ALLOC_ARG) {
+        AGFREE(pOD->optArg.argString);
+        pOD->fOptState &= ~OPTST_ALLOC_ARG;
+    }
+    pOD->optArg.argBool = res;
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/boolean.c */
diff --git a/libopts/check.c b/libopts/check.c
new file mode 100644 (file)
index 0000000..b4355b4
--- /dev/null
@@ -0,0 +1,164 @@
+/**
+ * @file check.c
+ *
+ * @brief consistency checks.
+ *
+ *  Time-stamp:      "2011-05-24 17:50:10 bkorb"
+ *
+ *  This file contains the routines that deal with processing quoted strings
+ *  into an internal format.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/**
+ *  Check for conflicts based on "must" and "cannot" attributes.
+ */
+static ag_bool
+has_conflict(tOptions * pOpts, tOptDesc * pOD)
+{
+    if (pOD->pOptMust != NULL) {
+        int const * pMust = pOD->pOptMust;
+
+        while (*pMust != NO_EQUIVALENT) {
+            tOptDesc * p = pOpts->pOptDesc + *(pMust++);
+            if (UNUSED_OPT(p)) {
+                const tOptDesc * pN = pOpts->pOptDesc + pMust[-1];
+                fprintf(stderr, zReqFmt, pOD->pz_Name, pN->pz_Name);
+                return AG_TRUE;
+            }
+        }
+    }
+
+    if (pOD->pOptCant != NULL) {
+        int const * pCant = pOD->pOptCant;
+
+        while (*pCant != NO_EQUIVALENT) {
+            tOptDesc * p = pOpts->pOptDesc + *(pCant++);
+            if (SELECTED_OPT(p)) {
+                const tOptDesc* pN = pOpts->pOptDesc + pCant[-1];
+                fprintf(stderr, zCantFmt, pOD->pz_Name, pN->pz_Name);
+                return AG_TRUE;
+            }
+        }
+    }
+
+    return AG_FALSE;
+}
+
+/**
+ *  Check that the option occurs often enough.  Too often is already checked.
+ */
+static ag_bool
+occurs_enough(tOptions * pOpts, tOptDesc * pOD)
+{
+    /*
+     *  IF the occurrence counts have been satisfied,
+     *  THEN there is no problem.
+     */
+    if (pOD->optOccCt >= pOD->optMinCt)
+        return AG_TRUE;
+
+    /*
+     *  IF MUST_SET means SET and PRESET are okay,
+     *  so min occurrence count doesn't count
+     */
+    if (  (pOD->fOptState & OPTST_MUST_SET)
+       && (pOD->fOptState & (OPTST_PRESET | OPTST_SET)) )
+        return AG_TRUE;
+
+    if (pOD->optMinCt > 1)
+         fprintf(stderr, zNotEnough, pOD->pz_Name, pOD->optMinCt);
+    else fprintf(stderr, zNeedOne, pOD->pz_Name);
+    return AG_FALSE;
+}
+
+/**
+ *  Verify option consistency.
+ *
+ *  Make sure that the argument list passes our consistency tests.
+ */
+LOCAL ag_bool
+is_consistent(tOptions * pOpts)
+{
+    tOptDesc * pOD   = pOpts->pOptDesc;
+    int        oCt   = pOpts->presetOptCt;
+
+    /*
+     *  FOR each of "oCt" options, ...
+     */
+    for (;;) {
+        /*
+         *  IF the current option was provided on the command line
+         *  THEN ensure that any "MUST" requirements are not
+         *       "DEFAULT" (unspecified) *AND* ensure that any
+         *       "CANT" options have not been SET or DEFINED.
+         */
+        if (SELECTED_OPT(pOD)) {
+            if (has_conflict(pOpts, pOD))
+                return AG_FALSE;
+        }
+
+        /*
+         *  IF       this option is not equivalenced to another,
+         *        OR it is equivalenced to itself (is the equiv. root)
+         *  THEN we need to make sure it occurs often enough.
+         */
+        if (  (pOD->optEquivIndex == NO_EQUIVALENT)
+           || (pOD->optEquivIndex == pOD->optIndex) )
+
+            if (! occurs_enough(pOpts, pOD))
+                return AG_FALSE;
+
+        if (--oCt <= 0)
+            break;
+        pOD++;
+    }
+
+    /*
+     *  IF we are stopping on errors, check to see if any remaining
+     *  arguments are required to be there or prohibited from being there.
+     */
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+
+        /*
+         *  Check for prohibition
+         */
+        if ((pOpts->fOptSet & OPTPROC_NO_ARGS) != 0) {
+            if (pOpts->origArgCt > pOpts->curOptIdx) {
+                fprintf(stderr, zNoArgs, pOpts->pzProgName);
+                return AG_FALSE;
+            }
+        }
+
+        /*
+         *  ELSE not prohibited, check for being required
+         */
+        else if ((pOpts->fOptSet & OPTPROC_ARGS_REQ) != 0) {
+            if (pOpts->origArgCt <= pOpts->curOptIdx) {
+                fprintf(stderr, zArgsMust, pOpts->pzProgName);
+                return AG_FALSE;
+            }
+        }
+    }
+
+    return AG_TRUE;
+}
diff --git a/libopts/compat/compat.h b/libopts/compat/compat.h
new file mode 100644 (file)
index 0000000..230aef9
--- /dev/null
@@ -0,0 +1,388 @@
+/*  -*- Mode: C -*-  */
+
+/**
+ * \file compat.h --- fake the preprocessor into handlng portability
+ *
+ *  Time-stamp:      "2010-07-16 15:11:57 bkorb"
+ *
+ *  compat.h is free software.
+ *  This file is part of AutoGen.
+ *
+ *  AutoGen Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoGen is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AutoGen is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  As a special exception, Bruce Korb gives permission for additional
+ *  uses of the text contained in the release of compat.h.
+ *
+ *  The exception is that, if you link the compat.h library with other
+ *  files to produce an executable, this does not by itself cause the
+ *  resulting executable to be covered by the GNU General Public License.
+ *  Your use of that executable is in no way restricted on account of
+ *  linking the compat.h library code into it.
+ *
+ *  This exception does not however invalidate any other reasons why
+ *  the executable file might be covered by the GNU General Public License.
+ *
+ *  This exception applies only to the code released by Bruce Korb under
+ *  the name compat.h.  If you copy code from other sources under the
+ *  General Public License into a copy of compat.h, as the General Public
+ *  License permits, the exception does not apply to the code that you add
+ *  in this way.  To avoid misleading anyone as to the status of such
+ *  modified files, you must delete this exception notice from them.
+ *
+ *  If you write modifications of your own for compat.h, it is your choice
+ *  whether to permit this exception to apply to your modifications.
+ *  If you do not wish that, delete this exception notice.
+ */
+#ifndef COMPAT_H_GUARD
+#define COMPAT_H_GUARD 1
+
+#if defined(HAVE_CONFIG_H)
+#  include <config.h>
+
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+#  include "windows-config.h"
+
+#else
+#  error "compat.h" requires "config.h"
+   choke me.
+#endif
+
+
+#ifndef HAVE_STRSIGNAL
+   char * strsignal( int signo );
+#endif
+
+#define  _GNU_SOURCE    1 /* for strsignal in GNU's libc */
+#define  __USE_GNU      1 /* exact same thing as above   */
+#define  __EXTENSIONS__ 1 /* and another way to call for it */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  SYSTEM HEADERS:
+ */
+#include <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#  include <sys/mman.h>
+#endif
+#include <sys/param.h>
+#if HAVE_SYS_PROCSET_H
+#  include <sys/procset.h>
+#endif
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#if defined( HAVE_SOLARIS_SYSINFO )
+#  include <sys/systeminfo.h>
+#elif defined( HAVE_UNAME_SYSCALL )
+#  include <sys/utsname.h>
+#endif
+
+#ifdef DAEMON_ENABLED
+#  if HAVE_SYS_STROPTS_H
+#  include <sys/stropts.h>
+#  endif
+
+#  if HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#  endif
+
+#  if ! defined(HAVE_SYS_POLL_H) && ! defined(HAVE_SYS_SELECT_H)
+#    error This system cannot support daemon processing
+     Choke Me.
+#  endif
+
+#  if HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+#  endif
+
+#  if HAVE_SYS_SELECT_H
+#  include <sys/select.h>
+#  endif
+
+#  if HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#  endif
+
+#  if HAVE_SYS_UN_H
+#  include <sys/un.h>
+#  endif
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  USER HEADERS:
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+
+/*
+ *  Directory opening stuff:
+ */
+# if defined (_POSIX_SOURCE)
+/* Posix does not require that the d_ino field be present, and some
+   systems do not provide it. */
+#    define REAL_DIR_ENTRY(dp) 1
+# else /* !_POSIX_SOURCE */
+#    define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+# endif /* !_POSIX_SOURCE */
+
+# if defined (HAVE_DIRENT_H)
+#   include <dirent.h>
+#   define D_NAMLEN(dirent) strlen((dirent)->d_name)
+# else /* !HAVE_DIRENT_H */
+#   define dirent direct
+#   define D_NAMLEN(dirent) (dirent)->d_namlen
+#   if defined (HAVE_SYS_NDIR_H)
+#     include <sys/ndir.h>
+#   endif /* HAVE_SYS_NDIR_H */
+#   if defined (HAVE_SYS_DIR_H)
+#     include <sys/dir.h>
+#   endif /* HAVE_SYS_DIR_H */
+#   if defined (HAVE_NDIR_H)
+#     include <ndir.h>
+#   endif /* HAVE_NDIR_H */
+# endif /* !HAVE_DIRENT_H */
+
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifndef O_NONBLOCK
+# define O_NONBLOCK FNDELAY
+#endif
+
+#if defined(HAVE_LIBGEN) && defined(HAVE_LIBGEN_H)
+#  include <libgen.h>
+#endif
+
+#if defined(HAVE_LIMITS_H)  /* this is also in options.h */
+#  include <limits.h>
+#elif defined(HAVE_SYS_LIMITS_H)
+#  include <sys/limits.h>
+#endif /* HAVE_LIMITS/SYS_LIMITS_H */
+
+#include <memory.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#if defined( HAVE_STDINT_H )
+#  include <stdint.h>
+#elif defined( HAVE_INTTYPES_H )
+#  include <inttypes.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <time.h>
+
+#ifdef HAVE_UTIME_H
+#  include <utime.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  FIXUPS and CONVIENCE STUFF:
+ */
+#ifdef __cplusplus
+#   define EXTERN extern "C"
+#else
+#   define EXTERN extern
+#endif
+
+/* some systems #def errno! and others do not declare it!! */
+#ifndef errno
+   extern int errno;
+#endif
+
+/* Some machines forget this! */
+
+# ifndef EXIT_FAILURE
+#   define EXIT_SUCCESS 0
+#   define EXIT_FAILURE 1
+# endif
+
+#ifndef NUL
+#  define NUL '\0'
+#endif
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+#if !defined (MAXPATHLEN) && defined (HAVE_SYS_PARAM_H)
+#  include <sys/param.h>
+#endif /* !MAXPATHLEN && HAVE_SYS_PARAM_H */
+
+#if !defined (MAXPATHLEN) && defined (PATH_MAX)
+#  define MAXPATHLEN PATH_MAX
+#endif /* !MAXPATHLEN && PATH_MAX */
+
+#if !defined (MAXPATHLEN) && defined(_MAX_PATH)
+#  define PATH_MAX _MAX_PATH
+#  define MAXPATHLEN _MAX_PATH
+#endif
+
+#if !defined (MAXPATHLEN)
+#  define MAXPATHLEN ((size_t)4096)
+#endif /* MAXPATHLEN */
+
+#define AG_PATH_MAX  ((size_t)MAXPATHLEN)
+
+#ifndef LONG_MAX
+#  define LONG_MAX      ~(1L << (8*sizeof(long) -1))
+#  define INT_MAX       ~(1 << (8*sizeof(int) -1))
+#endif
+
+#ifndef ULONG_MAX
+#  define ULONG_MAX     ~(OUL)
+#  define UINT_MAX      ~(OU)
+#endif
+
+#ifndef SHORT_MAX
+#  define SHORT_MAX     ~(1 << (8*sizeof(short) - 1))
+#else
+#  define USHORT_MAX    ~(OUS)
+#endif
+
+#ifndef HAVE_INT8_T
+  typedef signed char           int8_t;
+# define  HAVE_INT8_T           1
+#endif
+#ifndef HAVE_UINT8_T
+  typedef unsigned char         uint8_t;
+# define  HAVE_UINT8_T          1
+#endif
+#ifndef HAVE_INT16_T
+  typedef signed short          int16_t;
+# define  HAVE_INT16_T          1
+#endif
+#ifndef HAVE_UINT16_T
+  typedef unsigned short        uint16_t;
+# define  HAVE_UINT16_T         1
+#endif
+
+#ifndef HAVE_INT32_T
+# if SIZEOF_INT ==              4
+    typedef signed int          int32_t;
+# elif SIZEOF_LONG ==           4
+    typedef signed long         int32_t;
+# endif
+# define  HAVE_INT32_T          1
+#endif
+
+#ifndef HAVE_UINT32_T
+# if SIZEOF_INT ==              4
+    typedef unsigned int        uint32_t;
+# elif SIZEOF_LONG ==           4
+    typedef unsigned long       uint32_t;
+# else
+#   error Cannot create a uint32_t type.
+    Choke Me.
+# endif
+# define  HAVE_UINT32_T         1
+#endif
+
+#ifndef HAVE_INTPTR_T
+# if SIZEOF_CHARP == SIZEOF_LONG
+    typedef signed long         intptr_t;
+# else
+    typedef signed int          intptr_t;
+# endif
+# define  HAVE_INTPTR_T         1
+#endif
+
+#ifndef HAVE_UINTPTR_T
+# if SIZEOF_CHARP == SIZEOF_LONG
+    typedef unsigned long       intptr_t;
+# else
+    typedef unsigned int        intptr_t;
+# endif
+# define  HAVE_INTPTR_T         1
+#endif
+
+#ifndef HAVE_UINT_T
+  typedef unsigned int          uint_t;
+# define  HAVE_UINT_T           1
+#endif
+
+#ifndef HAVE_SIZE_T
+  typedef unsigned int          size_t;
+# define  HAVE_SIZE_T           1
+#endif
+#ifndef HAVE_WINT_T
+  typedef unsigned int          wint_t;
+# define  HAVE_WINT_T           1
+#endif
+#ifndef HAVE_PID_T
+  typedef signed int            pid_t;
+# define  HAVE_PID_T            1
+#endif
+
+/* redefine these for BSD style string libraries */
+#ifndef HAVE_STRCHR
+#  define strchr            index
+#  define strrchr           rindex
+#endif
+
+#ifdef USE_FOPEN_BINARY
+#  ifndef FOPEN_BINARY_FLAG
+#    define FOPEN_BINARY_FLAG   "b"
+#  endif
+#  ifndef FOPEN_TEXT_FLAG
+#    define FOPEN_TEXT_FLAG     "t"
+#  endif
+#else
+#  ifndef FOPEN_BINARY_FLAG
+#    define FOPEN_BINARY_FLAG
+#  endif
+#  ifndef FOPEN_TEXT_FLAG
+#    define FOPEN_TEXT_FLAG
+#  endif
+#endif
+
+#ifndef STR
+#  define _STR(s) #s
+#  define STR(s)  _STR(s)
+#endif
+
+/* ##### Pointer sized word ##### */
+
+/* FIXME:  the MAX stuff in here is broken! */
+#if SIZEOF_CHARP > SIZEOF_INT
+   typedef long t_word;
+   #define WORD_MAX  LONG_MAX
+   #define WORD_MIN  LONG_MIN
+#else /* SIZEOF_CHARP <= SIZEOF_INT */
+   typedef int t_word;
+   #define WORD_MAX  INT_MAX
+   #define WORD_MIN  INT_MIN
+#endif
+
+#endif /* COMPAT_H_GUARD */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of compat/compat.h */
diff --git a/libopts/compat/pathfind.c b/libopts/compat/pathfind.c
new file mode 100644 (file)
index 0000000..2d5b27d
--- /dev/null
@@ -0,0 +1,334 @@
+/*  -*- Mode: C -*-  */
+
+/* pathfind.c --- find a FILE  MODE along PATH */
+
+/*
+ * Author:           Gary V Vaughan <gvaughan@oranda.demon.co.uk>
+ * Time-stamp:       "2010-07-17 09:50:32 bkorb"
+ */
+
+/* Code: */
+
+#include "compat.h"
+#ifndef HAVE_PATHFIND
+#if defined(__windows__) && !defined(__CYGWIN__)
+char*
+pathfind( char const*  path,
+          char const*  fileName,
+          char const*  mode )
+{
+    return NULL;
+}
+#else
+
+static char* make_absolute( char const *string, char const *dot_path );
+static char* canonicalize_pathname( char *path );
+static char* extract_colon_unit( char* dir, char const *string, int *p_index );
+
+
+/*=export_func pathfind
+ *
+ * what: fild a file in a list of directories
+ *
+ * ifndef: HAVE_PATHFIND
+ *
+ * arg:  + char const* + path + colon separated list of search directories +
+ * arg:  + char const* + file + the name of the file to look for +
+ * arg:  + char const* + mode + the mode bits that must be set to match +
+ *
+ * ret_type:  char*
+ * ret_desc:  the path to the located file
+ *
+ * doc:
+ *
+ * pathfind looks for a a file with name "FILE" and "MODE" access
+ * along colon delimited "PATH", and returns the full pathname as a
+ * string, or NULL if not found.  If "FILE" contains a slash, then
+ * it is treated as a relative or absolute path and "PATH" is ignored.
+ *
+ * @strong{NOTE}: this function is compiled into @file{libopts} only if
+ * it is not natively supplied.
+ *
+ * The "MODE" argument is a string of option letters chosen from the
+ * list below:
+ * @example
+ *          Letter    Meaning
+ *          r         readable
+ *          w         writable
+ *          x         executable
+ *          f         normal file       (NOT IMPLEMENTED)
+ *          b         block special     (NOT IMPLEMENTED)
+ *          c         character special (NOT IMPLEMENTED)
+ *          d         directory         (NOT IMPLEMENTED)
+ *          p         FIFO (pipe)       (NOT IMPLEMENTED)
+ *          u         set user ID bit   (NOT IMPLEMENTED)
+ *          g         set group ID bit  (NOT IMPLEMENTED)
+ *          k         sticky bit        (NOT IMPLEMENTED)
+ *          s         size nonzero      (NOT IMPLEMENTED)
+ * @end example
+ *
+ * example:
+ * To find the "ls" command using the "PATH" environment variable:
+ * @example
+ *    #include <stdlib.h>
+ *    char* pz_ls = pathfind( getenv("PATH"), "ls", "rx" );
+ *    <<do whatever with pz_ls>>
+ *    free( pz_ls );
+ * @end example
+ * The path is allocated with @code{malloc(3C)}, so you must @code{free(3C)}
+ * the result.  Also, do not use unimplemented file modes.  :-)
+ *
+ * err:  returns NULL if the file is not found.
+=*/
+char*
+pathfind( char const*  path,
+          char const*  fileName,
+          char const*  mode )
+{
+    int   p_index   = 0;
+    int   mode_bits = 0;
+    char* pathName  = NULL;
+    char  zPath[ AG_PATH_MAX + 1 ];
+
+    if (strchr( mode, 'r' )) mode_bits |= R_OK;
+    if (strchr( mode, 'w' )) mode_bits |= W_OK;
+    if (strchr( mode, 'x' )) mode_bits |= X_OK;
+
+    /*
+     *  FOR each non-null entry in the colon-separated path, DO ...
+     */
+    for (;;) {
+        DIR*  dirP;
+        char* colon_unit = extract_colon_unit( zPath, path, &p_index );
+
+        /*
+         *  IF no more entries, THEN quit
+         */
+        if (colon_unit == NULL)
+            break;
+
+        dirP = opendir( colon_unit );
+
+        /*
+         *  IF the directory is inaccessable, THEN next directory
+         */
+        if (dirP == NULL)
+            continue;
+
+        /*
+         *  FOR every entry in the given directory, ...
+         */
+        for (;;) {
+            struct dirent *entP = readdir( dirP );
+
+            if (entP == (struct dirent*)NULL)
+                break;
+
+            /*
+             *  IF the file name matches the one we are looking for, ...
+             */
+            if (strcmp( entP->d_name, fileName ) == 0) {
+                char* pzFullName = make_absolute( fileName, colon_unit);
+
+                /*
+                 *  Make sure we can access it in the way we want
+                 */
+                if (access( pzFullName, mode_bits ) >= 0) {
+                    /*
+                     *  We can, so normalize the name and return it below
+                     */
+                    pathName = canonicalize_pathname( pzFullName );
+                }
+
+                free( (void*)pzFullName );
+                break;
+            }
+        }
+
+        closedir( dirP );
+
+        if (pathName != NULL)
+            break;
+    }
+
+    return pathName;
+}
+
+/*
+ * Turn STRING  (a pathname) into an  absolute  pathname, assuming  that
+ * DOT_PATH contains the symbolic location of  `.'.  This always returns
+ * a new string, even if STRING was an absolute pathname to begin with.
+ */
+static char*
+make_absolute( char const *string, char const *dot_path )
+{
+    char *result;
+    int result_len;
+
+    if (!dot_path || *string == '/') {
+        result = strdup( string );
+    } else {
+        if (dot_path && dot_path[0]) {
+            result = malloc( 2 + strlen( dot_path ) + strlen( string ) );
+            strcpy( result, dot_path );
+            result_len = strlen( result );
+            if (result[result_len - 1] != '/') {
+                result[result_len++] = '/';
+                result[result_len] = '\0';
+            }
+        } else {
+            result = malloc( 3 + strlen( string ) );
+            result[0] = '.'; result[1] = '/'; result[2] = '\0';
+            result_len = 2;
+        }
+
+        strcpy( result + result_len, string );
+    }
+
+    return result;
+}
+
+/*
+ * Canonicalize PATH, and return a  new path.  The new path differs from
+ * PATH in that:
+ *
+ *    Multiple `/'s     are collapsed to a single `/'.
+ *    Leading `./'s     are removed.
+ *    Trailing `/.'s    are removed.
+ *    Trailing `/'s     are removed.
+ *    Non-leading `../'s and trailing `..'s are handled by removing
+ *                    portions of the path.
+ */
+static char*
+canonicalize_pathname( char *path )
+{
+    int i, start;
+    char stub_char, *result;
+
+    /* The result cannot be larger than the input PATH. */
+    result = strdup( path );
+
+    stub_char = (*path == '/') ? '/' : '.';
+
+    /* Walk along RESULT looking for things to compact. */
+    i = 0;
+    while (result[i]) {
+        while (result[i] != '\0' && result[i] != '/')
+            i++;
+
+        start = i++;
+
+        /* If we didn't find any  slashes, then there is nothing left to
+         * do.
+         */
+        if (!result[start])
+            break;
+
+        /* Handle multiple `/'s in a row. */
+        while (result[i] == '/')
+            i++;
+
+#if !defined (apollo)
+        if ((start + 1) != i)
+#else
+        if ((start + 1) != i && (start != 0 || i != 2))
+#endif /* apollo */
+        {
+            strcpy( result + start + 1, result + i );
+            i = start + 1;
+        }
+
+        /* Handle backquoted `/'. */
+        if (start > 0 && result[start - 1] == '\\')
+            continue;
+
+        /* Check for trailing `/', and `.' by itself. */
+        if ((start && !result[i])
+            || (result[i] == '.' && !result[i+1])) {
+            result[--i] = '\0';
+            break;
+        }
+
+        /* Check for `../', `./' or trailing `.' by itself. */
+        if (result[i] == '.') {
+            /* Handle `./'. */
+            if (result[i + 1] == '/') {
+                strcpy( result + i, result + i + 1 );
+                i = (start < 0) ? 0 : start;
+                continue;
+            }
+
+            /* Handle `../' or trailing `..' by itself. */
+            if (result[i + 1] == '.' &&
+                (result[i + 2] == '/' || !result[i + 2])) {
+                while (--start > -1 && result[start] != '/')
+                    ;
+                strcpy( result + start + 1, result + i + 2 );
+                i = (start < 0) ? 0 : start;
+                continue;
+            }
+        }
+    }
+
+    if (!*result) {
+        *result = stub_char;
+        result[1] = '\0';
+    }
+
+    return result;
+}
+
+/*
+ * Given a  string containing units of information separated  by colons,
+ * return the next one  pointed to by (P_INDEX), or NULL if there are no
+ * more.  Advance (P_INDEX) to the character after the colon.
+ */
+static char*
+extract_colon_unit( char* pzDir, char const *string, int *p_index )
+{
+    char*  pzDest = pzDir;
+    int    ix     = *p_index;
+
+    if (string == NULL)
+        return NULL;
+
+    if ((unsigned)ix >= strlen( string ))
+        return NULL;
+
+    {
+        char const* pzSrc = string + ix;
+
+        while (*pzSrc == ':')  pzSrc++;
+
+        for (;;) {
+            char ch = (*(pzDest++) = *(pzSrc++));
+            switch (ch) {
+            case ':':
+                pzDest[-1] = NUL;
+            case NUL:
+                goto copy_done;
+            }
+
+            if ((pzDest - pzDir) >= AG_PATH_MAX)
+                break;
+        } copy_done:;
+
+        ix = pzSrc - string;
+    }
+
+    if (*pzDir == NUL)
+        return NULL;
+
+    *p_index = ix;
+    return pzDir;
+}
+#endif /* __windows__ / __CYGWIN__ */
+#endif /* HAVE_PATHFIND */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of compat/pathfind.c */
diff --git a/libopts/compat/snprintf.c b/libopts/compat/snprintf.c
new file mode 100644 (file)
index 0000000..fc91d63
--- /dev/null
@@ -0,0 +1,60 @@
+
+#ifndef HAVE_VPRINTF
+#include "choke-me: no vprintf and no snprintf"
+#endif
+
+#if defined(HAVE_STDARG_H)
+#  include <stdarg.h>
+#  ifndef   VA_START
+#    define VA_START(a, f)  va_start(a, f)
+#    define VA_END(a)       va_end(a)
+#  endif /* VA_START */
+#  define SNV_USING_STDARG_H
+
+#elif defined(HAVE_VARARGS_H)
+#  include <varargs.h>
+#  ifndef   VA_START
+#    define VA_START(a, f) va_start(a)
+#    define VA_END(a)    va_end(a)
+#  endif /* VA_START */
+#  undef  SNV_USING_STDARG_H
+
+#else
+#  include "must-have-stdarg-or-varargs"
+#endif
+
+static int
+snprintf(char *str, size_t n, char const *fmt, ...)
+{
+    va_list ap;
+    int rval;
+
+#ifdef VSPRINTF_CHARSTAR
+    char *rp;
+    VA_START(ap, fmt);
+    rp = vsprintf(str, fmt, ap);
+    VA_END(ap);
+    rval = strlen(rp);
+
+#else
+    VA_START(ap, fmt);
+    rval = vsprintf(str, fmt, ap);
+    VA_END(ap);
+#endif
+
+    if (rval > n) {
+        fprintf(stderr, "snprintf buffer overrun %d > %d\n", rval, (int)n);
+        abort();
+    }
+    return rval;
+}
+
+static int
+vsnprintf( char *str, size_t n, char const *fmt, va_list ap )
+{
+#ifdef VSPRINTF_CHARSTAR
+    return (strlen(vsprintf(str, fmt, ap)));
+#else
+    return (vsprintf(str, fmt, ap));
+#endif
+}
diff --git a/libopts/compat/strchr.c b/libopts/compat/strchr.c
new file mode 100644 (file)
index 0000000..413f999
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+   SYNOPSIS
+       #include <string.h>
+
+       char *strchr(char const *s, int c);
+
+       char *strrchr(char const *s, int c);
+
+   DESCRIPTION
+       The  strchr() function returns a pointer to the first occurrence of the
+       character c in the string s.
+
+       The strrchr() function returns a pointer to the last occurrence of  the
+       character c in the string s.
+
+       Here  "character"  means "byte" - these functions do not work with wide
+       or multi-byte characters.
+
+   RETURN VALUE
+       The strchr() and strrchr() functions return a pointer  to  the  matched
+       character or NULL if the character is not found.
+
+   CONFORMING TO
+       SVID 3, POSIX, BSD 4.3, ISO 9899
+*/
+
+char*
+strchr( char const *s, int c)
+{
+    do {
+        if ((unsigned)*s == (unsigned)c)
+            return s;
+
+    } while (*(++s) != NUL);
+
+    return NULL;
+}
+
+char*
+strrchr( char const *s, int c)
+{
+    char const *e = s + strlen(s);
+
+    for (;;) {
+        if (--e < s)
+            break;
+
+        if ((unsigned)*e == (unsigned)c)
+            return e;
+    }
+    return NULL;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of compat/strsignal.c */
diff --git a/libopts/compat/strdup.c b/libopts/compat/strdup.c
new file mode 100644 (file)
index 0000000..e2933a8
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Platforms without strdup ?!?!?!
+ */
+
+static char *
+strdup( char const *s )
+{
+    char *cp;
+
+    if (s == NULL)
+        return NULL;
+
+    cp = (char *) AGALOC((unsigned) (strlen(s)+1), "strdup");
+
+    if (cp != NULL)
+        (void) strcpy(cp, s);
+
+    return cp;
+}
diff --git a/libopts/compat/windows-config.h b/libopts/compat/windows-config.h
new file mode 100644 (file)
index 0000000..360af10
--- /dev/null
@@ -0,0 +1,145 @@
+
+/*
+ * Time-stamp:        "2010-02-24 08:39:04 bkorb"
+ *
+ *  This file is part of AutoGen.
+ *
+ *  AutoGen Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoGen is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AutoGen is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef WINDOWS_CONFIG_HACKERY
+#define WINDOWS_CONFIG_HACKERY 1
+
+/*
+ * The definitions below have been stolen from NTP's config.h for Windows.
+ * However, they may be kept here in order to keep libopts independent from
+ * the NTP project.
+ */
+#ifndef __windows__
+#  define __windows__ 4
+#endif
+
+/*
+ * Miscellaneous functions that Microsoft maps
+ * to other names
+ *
+ * #define inline __inline
+ * #define vsnprintf _vsnprintf
+ */
+#define snprintf _snprintf
+/*
+ * #define stricmp _stricmp
+ * #define strcasecmp _stricmp
+ * #define isascii __isascii
+ * #define finite _finite
+ * #define random      rand
+ * #define srandom     srand
+ */
+
+#define SIZEOF_INT   4
+#define SIZEOF_CHARP 4
+#define SIZEOF_LONG  4
+#define SIZEOF_SHORT 2
+
+typedef unsigned long uintptr_t;
+
+/*
+ * # define HAVE_NET_IF_H
+ * # define QSORT_USES_VOID_P
+ * # define HAVE_SETVBUF
+ * # define HAVE_VSPRINTF
+ * # define HAVE_SNPRINTF
+ * # define HAVE_VSNPRINTF
+ * # define HAVE_PROTOTYPES             /* from ntpq.mak * /
+ * # define HAVE_MEMMOVE
+ * # define HAVE_TERMIOS_H
+ * # define HAVE_ERRNO_H
+ * # define HAVE_STDARG_H
+ * # define HAVE_NO_NICE
+ * # define HAVE_MKTIME
+ * # define TIME_WITH_SYS_TIME
+ * # define HAVE_IO_COMPLETION_PORT
+ * # define ISC_PLATFORM_NEEDNTOP
+ * # define ISC_PLATFORM_NEEDPTON
+ * # define NEED_S_CHAR_TYPEDEF
+ * # define USE_PROTOTYPES              /* for ntp_types.h * /
+ *
+ * #define ULONG_CONST(a) a ## UL
+ */
+
+#define HAVE_LIMITS_H   1
+#define HAVE_STRDUP     1
+#define HAVE_STRCHR     1
+#define HAVE_FCNTL_H    1
+
+/*
+ * VS.NET's version of wspiapi.h has a bug in it
+ * where it assigns a value to a variable inside
+ * an if statement. It should be comparing them.
+ * We prevent inclusion since we are not using this
+ * code so we don't have to see the warning messages
+ */
+#ifndef _WSPIAPI_H_
+#define _WSPIAPI_H_
+#endif
+
+/* Prevent inclusion of winsock.h in windows.h */
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_
+#endif
+
+#ifndef __RPCASYNC_H__
+#define __RPCASYNC_H__
+#endif
+
+/* Include Windows headers */
+#include <windows.h>
+#include <winsock2.h>
+#include <limits.h>
+
+/*
+ * Compatibility declarations for Windows, assuming SYS_WINNT
+ * has been defined.
+ */
+#define strdup  _strdup
+#define stat    _stat       /* struct stat from <sys/stat.h> */
+#define unlink  _unlink
+#define fchmod( _x, _y );
+#define ssize_t SSIZE_T
+
+#include <io.h>
+#define open    _open
+#define close   _close
+#define read    _read
+#define write   _write
+#define lseek   _lseek
+#define pipe    _pipe
+#define dup2    _dup2
+
+#define O_RDWR     _O_RDWR
+#define O_RDONLY   _O_RDONLY
+#define O_EXCL     _O_EXCL
+
+#ifndef S_ISREG
+#  define S_IFREG _S_IFREG
+#  define       S_ISREG(mode)   (((mode) & S_IFREG) == S_IFREG)
+#endif
+
+#ifndef S_ISDIR
+#  define S_IFDIR _S_IFDIR
+#  define       S_ISDIR(mode)   (((mode) & S_IFDIR) == S_IFDIR)
+#endif
+
+#endif /* WINDOWS_CONFIG_HACKERY */
diff --git a/libopts/configfile.c b/libopts/configfile.c
new file mode 100644 (file)
index 0000000..758ce27
--- /dev/null
@@ -0,0 +1,1419 @@
+/**
+ * \file configfile.c
+ *
+ *  Time-stamp:      "2011-12-17 12:51:30 bkorb"
+ *
+ *  configuration/rc/ini file handling.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+file_preset(tOptions * opts, char const * fname, int dir);
+
+static char*
+handle_comment(char* pzText);
+
+static char *
+handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir);
+
+static char *
+handle_directive(tOptions * pOpts, char * pzText);
+
+static char *
+aoflags_directive(tOptions * pOpts, char * pzText);
+
+static char *
+program_directive(tOptions * pOpts, char * pzText);
+
+static char *
+handle_section(tOptions * pOpts, char * pzText);
+
+static int
+parse_xml_encoding(char ** ppz);
+
+static char *
+trim_xml_text(char * pztxt, char const * pznm, tOptionLoadMode mode);
+
+static void
+cook_xml_text(char * pzData);
+
+static char *
+handle_struct(tOptions * pOpts, tOptState * pOS, char * pzText, int dir);
+
+static char*
+parse_keyword(tOptions * pOpts, char * pzText, tOptionValue * pType);
+
+static char*
+parse_set_mem(tOptions * pOpts, char * pzText, tOptionValue * pType);
+
+static char *
+parse_value(char * pzText, tOptionValue * pType);
+
+static char *
+skip_unkn(char* pzText);
+/* = = = END-STATIC-FORWARD = = = */
+
+
+/*=export_func  configFileLoad
+ *
+ * what:  parse a configuration file
+ * arg:   + char const*     + pzFile + the file to load +
+ *
+ * ret_type:  const tOptionValue*
+ * ret_desc:  An allocated, compound value structure
+ *
+ * doc:
+ *  This routine will load a named configuration file and parse the
+ *  text as a hierarchically valued option.  The option descriptor
+ *  created from an option definition file is not used via this interface.
+ *  The returned value is "named" with the input file name and is of
+ *  type "@code{OPARG_TYPE_HIERARCHY}".  It may be used in calls to
+ *  @code{optionGetValue()}, @code{optionNextValue()} and
+ *  @code{optionUnloadNested()}.
+ *
+ * err:
+ *  If the file cannot be loaded or processed, @code{NULL} is returned and
+ *  @var{errno} is set.  It may be set by a call to either @code{open(2)}
+ *  @code{mmap(2)} or other file system calls, or it may be:
+ *  @itemize @bullet
+ *  @item
+ *  @code{ENOENT} - the file was empty.
+ *  @item
+ *  @code{EINVAL} - the file contents are invalid -- not properly formed.
+ *  @item
+ *  @code{ENOMEM} - not enough memory to allocate the needed structures.
+ *  @end itemize
+=*/
+const tOptionValue*
+configFileLoad(char const* pzFile)
+{
+    tmap_info_t   cfgfile;
+    tOptionValue* pRes = NULL;
+    tOptionLoadMode save_mode = option_load_mode;
+
+    char* pzText =
+        text_mmap(pzFile, PROT_READ, MAP_PRIVATE, &cfgfile);
+
+    if (TEXT_MMAP_FAILED_ADDR(pzText))
+        return NULL; /* errno is set */
+
+    option_load_mode = OPTION_LOAD_COOKED;
+    pRes = optionLoadNested(pzText, pzFile, strlen(pzFile));
+
+    if (pRes == NULL) {
+        int err = errno;
+        text_munmap(&cfgfile);
+        errno = err;
+    } else
+        text_munmap(&cfgfile);
+
+    option_load_mode = save_mode;
+    return pRes;
+}
+
+
+/*=export_func  optionFindValue
+ *
+ * what:  find a hierarcicaly valued option instance
+ * arg:   + const tOptDesc* + pOptDesc + an option with a nested arg type +
+ * arg:   + char const*     + name     + name of value to find +
+ * arg:   + char const*     + value    + the matching value    +
+ *
+ * ret_type:  const tOptionValue*
+ * ret_desc:  a compound value structure
+ *
+ * doc:
+ *  This routine will find an entry in a nested value option or configurable.
+ *  It will search through the list and return a matching entry.
+ *
+ * err:
+ *  The returned result is NULL and errno is set:
+ *  @itemize @bullet
+ *  @item
+ *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
+ *  hierarchical option value.
+ *  @item
+ *  @code{ENOENT} - no entry matched the given name.
+ *  @end itemize
+=*/
+const tOptionValue*
+optionFindValue(const tOptDesc* pOptDesc, char const* pzName,
+                char const* pzVal)
+{
+    const tOptionValue* pRes = NULL;
+
+    if (  (pOptDesc == NULL)
+       || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY))  {
+        errno = EINVAL;
+    }
+
+    else if (pOptDesc->optCookie == NULL) {
+        errno = ENOENT;
+    }
+
+    else do {
+        tArgList* pAL = pOptDesc->optCookie;
+        int    ct   = pAL->useCt;
+        void** ppOV = (void**)(pAL->apzArgs);
+
+        if (ct == 0) {
+            errno = ENOENT;
+            break;
+        }
+
+        if (pzName == NULL) {
+            pRes = (tOptionValue*)*ppOV;
+            break;
+        }
+
+        while (--ct >= 0) {
+            const tOptionValue* pOV = *(ppOV++);
+            const tOptionValue* pRV = optionGetValue(pOV, pzName);
+
+            if (pRV == NULL)
+                continue;
+
+            if (pzVal == NULL) {
+                pRes = pOV;
+                break;
+            }
+        }
+        if (pRes == NULL)
+            errno = ENOENT;
+    } while (0);
+
+    return pRes;
+}
+
+
+/*=export_func  optionFindNextValue
+ *
+ * what:  find a hierarcicaly valued option instance
+ * arg:   + const tOptDesc* + pOptDesc + an option with a nested arg type +
+ * arg:   + const tOptionValue* + pPrevVal + the last entry +
+ * arg:   + char const*     + name     + name of value to find +
+ * arg:   + char const*     + value    + the matching value    +
+ *
+ * ret_type:  const tOptionValue*
+ * ret_desc:  a compound value structure
+ *
+ * doc:
+ *  This routine will find the next entry in a nested value option or
+ *  configurable.  It will search through the list and return the next entry
+ *  that matches the criteria.
+ *
+ * err:
+ *  The returned result is NULL and errno is set:
+ *  @itemize @bullet
+ *  @item
+ *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
+ *  hierarchical option value.
+ *  @item
+ *  @code{ENOENT} - no entry matched the given name.
+ *  @end itemize
+=*/
+tOptionValue const *
+optionFindNextValue(const tOptDesc * pOptDesc, const tOptionValue * pPrevVal,
+                    char const * pzName, char const * pzVal)
+{
+    int foundOldVal = 0;
+    tOptionValue* pRes = NULL;
+
+    if (  (pOptDesc == NULL)
+       || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY))  {
+        errno = EINVAL;
+    }
+
+    else if (pOptDesc->optCookie == NULL) {
+        errno = ENOENT;
+    }
+
+    else do {
+        tArgList* pAL = pOptDesc->optCookie;
+        int    ct   = pAL->useCt;
+        void** ppOV = (void**)pAL->apzArgs;
+
+        if (ct == 0) {
+            errno = ENOENT;
+            break;
+        }
+
+        while (--ct >= 0) {
+            tOptionValue* pOV = *(ppOV++);
+            if (foundOldVal) {
+                pRes = pOV;
+                break;
+            }
+            if (pOV == pPrevVal)
+                foundOldVal = 1;
+        }
+        if (pRes == NULL)
+            errno = ENOENT;
+    } while (0);
+
+    return pRes;
+}
+
+
+/*=export_func  optionGetValue
+ *
+ * what:  get a specific value from a hierarcical list
+ * arg:   + const tOptionValue* + pOptValue + a hierarchcal value +
+ * arg:   + char const*   + valueName + name of value to get +
+ *
+ * ret_type:  const tOptionValue*
+ * ret_desc:  a compound value structure
+ *
+ * doc:
+ *  This routine will find an entry in a nested value option or configurable.
+ *  If "valueName" is NULL, then the first entry is returned.  Otherwise,
+ *  the first entry with a name that exactly matches the argument will be
+ *  returned.  If there is no matching value, NULL is returned and errno is
+ *  set to ENOENT. If the provided option value is not a hierarchical value,
+ *  NULL is also returned and errno is set to EINVAL.
+ *
+ * err:
+ *  The returned result is NULL and errno is set:
+ *  @itemize @bullet
+ *  @item
+ *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
+ *  hierarchical option value.
+ *  @item
+ *  @code{ENOENT} - no entry matched the given name.
+ *  @end itemize
+=*/
+const tOptionValue*
+optionGetValue(tOptionValue const * pOld, char const * pzValName)
+{
+    tArgList *     pAL;
+    tOptionValue * pRes = NULL;
+
+    if ((pOld == NULL) || (pOld->valType != OPARG_TYPE_HIERARCHY)) {
+        errno = EINVAL;
+        return pRes;
+    }
+    pAL = pOld->v.nestVal;
+
+    if (pAL->useCt > 0) {
+        int     ct    = pAL->useCt;
+        void ** papOV = (void**)(pAL->apzArgs);
+
+        if (pzValName == NULL) {
+            pRes = (tOptionValue*)*papOV;
+
+        } else do {
+            tOptionValue * pOV = *(papOV++);
+            if (strcmp(pOV->pzName, pzValName) == 0) {
+                pRes = pOV;
+                break;
+            }
+        } while (--ct > 0);
+    }
+    if (pRes == NULL)
+        errno = ENOENT;
+    return pRes;
+}
+
+
+/*=export_func  optionNextValue
+ *
+ * what:  get the next value from a hierarchical list
+ * arg:   + const tOptionValue* + pOptValue + a hierarchcal list value +
+ * arg:   + const tOptionValue* + pOldValue + a value from this list   +
+ *
+ * ret_type:  const tOptionValue*
+ * ret_desc:  a compound value structure
+ *
+ * doc:
+ *  This routine will return the next entry after the entry passed in.  At the
+ *  end of the list, NULL will be returned.  If the entry is not found on the
+ *  list, NULL will be returned and "@var{errno}" will be set to EINVAL.
+ *  The "@var{pOldValue}" must have been gotten from a prior call to this
+ *  routine or to "@code{opitonGetValue()}".
+ *
+ * err:
+ *  The returned result is NULL and errno is set:
+ *  @itemize @bullet
+ *  @item
+ *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
+ *  hierarchical option value or @code{pOldValue} does not point to a
+ *  member of that option value.
+ *  @item
+ *  @code{ENOENT} - the supplied @code{pOldValue} pointed to the last entry.
+ *  @end itemize
+=*/
+tOptionValue const *
+optionNextValue(tOptionValue const * pOVList,tOptionValue const * pOldOV )
+{
+    tArgList*     pAL;
+    tOptionValue* pRes = NULL;
+    int           err  = EINVAL;
+
+    if ((pOVList == NULL) || (pOVList->valType != OPARG_TYPE_HIERARCHY)) {
+        errno = EINVAL;
+        return NULL;
+    }
+    pAL = pOVList->v.nestVal;
+    {
+        int    ct    = pAL->useCt;
+        void** papNV = (void**)(pAL->apzArgs);
+
+        while (ct-- > 0) {
+            tOptionValue* pNV = *(papNV++);
+            if (pNV == pOldOV) {
+                if (ct == 0) {
+                    err = ENOENT;
+
+                } else {
+                    err  = 0;
+                    pRes = (tOptionValue*)*papNV;
+                }
+                break;
+            }
+        }
+    }
+    if (err != 0)
+        errno = err;
+    return pRes;
+}
+
+
+/**
+ *  Load a file containing presetting information (a configuration file).
+ */
+static void
+file_preset(tOptions * opts, char const * fname, int dir)
+{
+    tmap_info_t   cfgfile;
+    tOptState     optst = OPTSTATE_INITIALIZER(PRESET);
+    unsigned long st_flags = optst.flags;
+    char *        ftext =
+        text_mmap(fname, PROT_READ|PROT_WRITE, MAP_PRIVATE, &cfgfile);
+
+    if (TEXT_MMAP_FAILED_ADDR(ftext))
+        return;
+
+    if (dir == DIRECTION_CALLED) {
+        st_flags = OPTST_DEFINED;
+        dir   = DIRECTION_PROCESS;
+    }
+
+    /*
+     *  IF this is called via "optionProcess", then we are presetting.
+     *  This is the default and the PRESETTING bit will be set.
+     *  If this is called via "optionFileLoad", then the bit is not set
+     *  and we consider stuff set herein to be "set" by the client program.
+     */
+    if ((opts->fOptSet & OPTPROC_PRESETTING) == 0)
+        st_flags = OPTST_SET;
+
+    do  {
+        optst.flags = st_flags;
+        while (IS_WHITESPACE_CHAR(*ftext))  ftext++;
+
+        if (IS_VAR_FIRST_CHAR(*ftext)) {
+            ftext = handle_cfg(opts, &optst, ftext, dir);
+
+        } else switch (*ftext) {
+        case '<':
+            if (IS_VAR_FIRST_CHAR(ftext[1]))
+                ftext = handle_struct(opts, &optst, ftext, dir);
+
+            else switch (ftext[1]) {
+            case '?':
+                ftext = handle_directive(opts, ftext);
+                break;
+
+            case '!':
+                ftext = handle_comment(ftext);
+                break;
+
+            case '/':
+                ftext = strchr(ftext + 2, '>');
+                if (ftext++ != NULL)
+                    break;
+
+            default:
+                goto all_done;
+            }
+            break;
+
+        case '[':
+            ftext = handle_section(opts, ftext);
+            break;
+
+        case '#':
+            ftext = strchr(ftext + 1, '\n');
+            break;
+
+        default:
+            goto all_done; /* invalid format */
+        }
+    } while (ftext != NULL);
+
+all_done:
+    text_munmap(&cfgfile);
+}
+
+
+/**
+ *  "pzText" points to a "<!" sequence.
+ *  Theoretically, we should ensure that it begins with "<!--",
+ *  but actually I don't care that much.  It ends with "-->".
+ */
+static char*
+handle_comment(char* pzText)
+{
+    char* pz = strstr(pzText, "-->");
+    if (pz != NULL)
+        pz += 3;
+    return pz;
+}
+
+
+/**
+ *  "pzText" points to the start of some value name.
+ *  The end of the entry is the end of the line that is not preceded by
+ *  a backslash escape character.  The string value is always processed
+ *  in "cooked" mode.
+ */
+static char *
+handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir)
+{
+    char* pzName = pzText++;
+    char* pzEnd  = strchr(pzText, '\n');
+
+    if (pzEnd == NULL)
+        return pzText + strlen(pzText);
+
+    while (IS_VALUE_NAME_CHAR(*pzText)) pzText++;
+    while (IS_WHITESPACE_CHAR(*pzText)) pzText++;
+    if (pzText > pzEnd) {
+    name_only:
+        *pzEnd++ = NUL;
+        loadOptionLine(pOpts, pOS, pzName, dir, OPTION_LOAD_UNCOOKED);
+        return pzEnd;
+    }
+
+    /*
+     *  Either the first character after the name is a ':' or '=',
+     *  or else we must have skipped over white space.  Anything else
+     *  is an invalid format and we give up parsing the text.
+     */
+    if ((*pzText == '=') || (*pzText == ':')) {
+        while (IS_WHITESPACE_CHAR(*++pzText))   ;
+        if (pzText > pzEnd)
+            goto name_only;
+    } else if (! IS_WHITESPACE_CHAR(pzText[-1]))
+        return NULL;
+
+    /*
+     *  IF the value is continued, remove the backslash escape and push "pzEnd"
+     *  on to a newline *not* preceded by a backslash.
+     */
+    if (pzEnd[-1] == '\\') {
+        char* pcD = pzEnd-1;
+        char* pcS = pzEnd;
+
+        for (;;) {
+            char ch = *(pcS++);
+            switch (ch) {
+            case NUL:
+                pcS = NULL;
+
+            case '\n':
+                *pcD = NUL;
+                pzEnd = pcS;
+                goto copy_done;
+
+            case '\\':
+                if (*pcS == '\n') {
+                    ch = *(pcS++);
+                }
+                /* FALLTHROUGH */
+            default:
+                *(pcD++) = ch;
+            }
+        } copy_done:;
+
+    } else {
+        /*
+         *  The newline was not preceded by a backslash.  NUL it out
+         */
+        *(pzEnd++) = NUL;
+    }
+
+    /*
+     *  "pzName" points to what looks like text for one option/configurable.
+     *  It is NUL terminated.  Process it.
+     */
+    loadOptionLine(pOpts, pOS, pzName, dir, OPTION_LOAD_UNCOOKED);
+
+    return pzEnd;
+}
+
+
+/**
+ *  "pzText" points to a "<?" sequence.
+ *  We handle "<?program" and "<?auto-options" directives.
+ *  All others are treated as comments.
+ */
+static char *
+handle_directive(tOptions * pOpts, char * pzText)
+{
+#   define DIRECTIVE_TABLE                      \
+    _dt_(zCfgProg,     program_directive)       \
+    _dt_(zCfgAO_Flags, aoflags_directive)
+
+    typedef char * (directive_func_t)(tOptions *, char *);
+#   define _dt_(_s, _fn) _fn,
+    static directive_func_t * dir_disp[] = {
+        DIRECTIVE_TABLE
+    };
+#   undef  _dt_
+
+#   define _dt_(_s, _fn) 1 +
+    static int  const   dir_ct  = DIRECTIVE_TABLE 0;
+    static char const * dir_names[DIRECTIVE_TABLE 0];
+#   undef _dt_
+
+    int    ix;
+
+    if (dir_names[0] == NULL) {
+        ix = 0;
+#   define _dt_(_s, _fn) dir_names[ix++] = _s;
+        DIRECTIVE_TABLE;
+#   undef _dt_
+    }
+
+    for (ix = 0; ix < dir_ct; ix++) {
+        size_t len = strlen(dir_names[ix]);
+        if (  (strncmp(pzText + 2, dir_names[ix], len) == 0)
+           && (! IS_VALUE_NAME_CHAR(pzText[len+2])) )
+            return dir_disp[ix](pOpts, pzText + len + 2);
+    }
+
+    /*
+     *  We don't know what this is.  Skip it.
+     */
+    pzText = strchr(pzText+2, '>');
+    if (pzText != NULL)
+        pzText++;
+    return pzText;
+}
+
+/**
+ *  handle AutoOpts mode flags
+ */
+static char *
+aoflags_directive(tOptions * pOpts, char * pzText)
+{
+    char * pz = pzText;
+
+    while (IS_WHITESPACE_CHAR(*++pz))  ;
+    pzText = strchr(pz, '>');
+    if (pzText != NULL) {
+
+        size_t len  = pzText - pz;
+        char * ftxt = AGALOC(len + 1, "aoflags");
+
+        memcpy(ftxt, pz, len);
+        ftxt[len] = NUL;
+        set_usage_flags(pOpts, ftxt);
+        AGFREE(ftxt);
+
+        pzText++;
+    }
+
+    return pzText;
+}
+
+/**
+ * handle program segmentation of config file.
+ */
+static char *
+program_directive(tOptions * pOpts, char * pzText)
+{
+    static char const ttlfmt[] = "<?";
+    size_t ttl_len  = sizeof(ttlfmt) + strlen(zCfgProg);
+    char * ttl      = AGALOC(ttl_len, "prog title");
+    size_t name_len = strlen(pOpts->pzProgName);
+
+    memcpy(ttl, ttlfmt, sizeof(ttlfmt) - 1);
+    memcpy(ttl + sizeof(ttlfmt) - 1, zCfgProg, ttl_len - (sizeof(ttlfmt) - 1));
+
+    do  {
+        while (IS_WHITESPACE_CHAR(*++pzText))  ;
+
+        if (  (strneqvcmp(pzText, pOpts->pzProgName, (int)name_len) == 0)
+           && (IS_END_XML_TOKEN_CHAR(pzText[name_len])) ) {
+            pzText += name_len;
+            break;
+        }
+
+        pzText = strstr(pzText, ttl);
+    } while (pzText != NULL);
+
+    AGFREE(ttl);
+    if (pzText != NULL)
+        for (;;) {
+            if (*pzText == NUL) {
+                pzText = NULL;
+                break;
+            }
+            if (*(pzText++) == '>')
+                break;
+        }
+
+    return pzText;
+}
+
+
+/**
+ *  "pzText" points to a '[' character.
+ *  The "traditional" [PROG_NAME] segmentation of the config file.
+ *  Do not ever mix with the "<?program prog-name>" variation.
+ */
+static char *
+handle_section(tOptions * pOpts, char * pzText)
+{
+    size_t len = strlen(pOpts->pzPROGNAME);
+    if (   (strncmp(pzText+1, pOpts->pzPROGNAME, len) == 0)
+        && (pzText[len+1] == ']'))
+        return strchr(pzText + len + 2, '\n');
+
+    if (len > 16)
+        return NULL;
+
+    {
+        char z[24];
+        sprintf(z, "[%s]", pOpts->pzPROGNAME);
+        pzText = strstr(pzText, z);
+    }
+
+    if (pzText != NULL)
+        pzText = strchr(pzText, '\n');
+    return pzText;
+}
+
+/**
+ * parse XML encodings
+ */
+static int
+parse_xml_encoding(char ** ppz)
+{
+#   define XMLTABLE             \
+        _xmlNm_(amp,   '&')     \
+        _xmlNm_(lt,    '<')     \
+        _xmlNm_(gt,    '>')     \
+        _xmlNm_(ff,    '\f')    \
+        _xmlNm_(ht,    '\t')    \
+        _xmlNm_(cr,    '\r')    \
+        _xmlNm_(vt,    '\v')    \
+        _xmlNm_(bel,   '\a')    \
+        _xmlNm_(nl,    '\n')    \
+        _xmlNm_(space, ' ')     \
+        _xmlNm_(quot,  '"')     \
+        _xmlNm_(apos,  '\'')
+
+    static struct {
+        char const * const  nm_str;
+        unsigned short      nm_len;
+        short               nm_val;
+    } const xml_names[] = {
+#   define _xmlNm_(_n, _v) { #_n ";", sizeof(#_n), _v },
+        XMLTABLE
+#   undef  _xmlNm_
+#   undef XMLTABLE
+    };
+
+    static int const nm_ct = sizeof(xml_names) / sizeof(xml_names[0]);
+    int    base = 10;
+
+    char * pz = *ppz;
+
+    if (*pz == '#') {
+        pz++;
+        goto parse_number;
+    }
+
+    if (IS_DEC_DIGIT_CHAR(*pz)) {
+        unsigned long v;
+
+    parse_number:
+        switch (*pz) {
+        case 'x': case 'X':
+            /*
+             * Some forms specify hex with:  &#xNN;
+             */
+            base = 16;
+            pz++;
+            break;
+
+        case '0':
+            /*
+             *  &#0022; is hex and &#22; is decimal.  Cool.
+             *  Ya gotta love it.
+             */
+            if (pz[1] == '0')
+                base = 16;
+            break;
+        }
+
+        v = strtoul(pz, &pz, base);
+        if ((*pz != ';') || (v > 0x7F))
+            return NUL;
+        *ppz = pz + 1;
+        return (int)v;
+    }
+
+    {
+        int ix = 0;
+        do  {
+            if (strncmp(pz, xml_names[ix].nm_str, xml_names[ix].nm_len)
+                == 0) {
+                *ppz = pz + xml_names[ix].nm_len;
+                return xml_names[ix].nm_val;
+            }
+        } while (++ix < nm_ct);
+    }
+
+    return NUL;
+}
+
+/**
+ * Find the end marker for the named section of XML.
+ * Trim that text there, trimming trailing white space for all modes
+ * except for OPTION_LOAD_UNCOOKED.
+ */
+static char *
+trim_xml_text(char * pztxt, char const * pznm, tOptionLoadMode mode)
+{
+    static char const fmt[] = "</%s>";
+    char   z[64], *pz = z;
+    size_t len = strlen(pznm) + sizeof(fmt) - 2 /* for %s */;
+
+    if (len > sizeof(z))
+        pz = AGALOC(len, "scan name");
+
+    sprintf(pz, fmt, pznm);
+    *pztxt = ' ';
+    pztxt = strstr(pztxt, pz);
+    if (pz != z) AGFREE(pz);
+
+    if (pztxt == NULL)
+        return pztxt;
+
+    if (mode != OPTION_LOAD_UNCOOKED)
+        while (IS_WHITESPACE_CHAR(pztxt[-1]))   len++, pztxt--;
+
+    *pztxt = NUL;
+    return pztxt + len - 1 /* for NUL byte */;
+}
+
+/**
+ */
+static void
+cook_xml_text(char * pzData)
+{
+    char * pzs = pzData;
+    char * pzd = pzData;
+    char   bf[4];
+    bf[2] = NUL;
+
+    for (;;) {
+        int ch = ((int)*(pzs++)) & 0xFF;
+        switch (ch) {
+        case NUL:
+            *pzd = NUL;
+            return;
+
+        case '&':
+            *(pzd++) = \
+                ch = parse_xml_encoding(&pzs);
+            if (ch == NUL)
+                return;
+            break;
+
+        case '%':
+            bf[0] = *(pzs++);
+            bf[1] = *(pzs++);
+            if ((bf[0] == NUL) || (bf[1] == NUL)) {
+                *pzd = NUL;
+                return;
+            }
+
+            ch = strtoul(bf, NULL, 16);
+            /* FALLTHROUGH */
+
+        default:
+            *(pzd++) = ch;
+        }
+    }
+}
+
+/**
+ *  "pzText" points to a '<' character, followed by an alpha.
+ *  The end of the entry is either the "/>" following the name, or else a
+ *  "</name>" string.
+ */
+static char *
+handle_struct(tOptions * pOpts, tOptState * pOS, char * pzText, int dir)
+{
+    tOptionLoadMode mode = option_load_mode;
+    tOptionValue    valu;
+
+    char* pzName = ++pzText;
+    char* pzData;
+    char* pcNulPoint;
+
+    while (IS_VALUE_NAME_CHAR(*pzText))  pzText++;
+    pcNulPoint = pzText;
+    valu.valType = OPARG_TYPE_STRING;
+
+    switch (*pzText) {
+    case ' ':
+    case '\t':
+        pzText = parseAttributes(pOpts, pzText, &mode, &valu);
+        if (*pzText == '>')
+            break;
+        if (*pzText != '/')
+            return NULL;
+        /* FALLTHROUGH */
+
+    case '/':
+        if (pzText[1] != '>')
+            return NULL;
+        *pzText = NUL;
+        pzText += 2;
+        loadOptionLine(pOpts, pOS, pzName, dir, mode);
+        return pzText;
+
+    case '>':
+        break;
+
+    default:
+        pzText = strchr(pzText, '>');
+        if (pzText != NULL)
+            pzText++;
+        return pzText;
+    }
+
+    /*
+     *  If we are here, we have a value.  "pzText" points to a closing angle
+     *  bracket.  Separate the name from the value for a moment.
+     */
+    *pcNulPoint = NUL;
+    pzData = ++pzText;
+    pzText = trim_xml_text(pzText, pzName, mode);
+    if (pzText == NULL)
+        return pzText;
+
+    /*
+     *  Rejoin the name and value for parsing by "loadOptionLine()".
+     *  Erase any attributes parsed by "parseAttributes()".
+     */
+    memset(pcNulPoint, ' ', pzData - pcNulPoint);
+
+    /*
+     *  If we are getting a "string" value that is to be cooked,
+     *  then process the XML-ish &xx; XML-ish and %XX hex characters.
+     */
+    if (  (valu.valType == OPARG_TYPE_STRING)
+       && (mode == OPTION_LOAD_COOKED))
+        cook_xml_text(pzData);
+
+    /*
+     *  "pzName" points to what looks like text for one option/configurable.
+     *  It is NUL terminated.  Process it.
+     */
+    loadOptionLine(pOpts, pOS, pzName, dir, mode);
+
+    return pzText;
+}
+
+
+/**
+ *  Load a configuration file.  This may be invoked either from
+ *  scanning the "homerc" list, or from a specific file request.
+ *  (see "optionFileLoad()", the implementation for --load-opts)
+ */
+LOCAL void
+intern_file_load(tOptions* pOpts)
+{
+    uint32_t  svfl;
+    int       idx;
+    int       inc;
+    char      zFileName[ AG_PATH_MAX+1 ];
+
+    if (pOpts->papzHomeList == NULL)
+        return;
+
+    svfl = pOpts->fOptSet;
+    inc  = DIRECTION_PRESET;
+
+    /*
+     *  Never stop on errors in config files.
+     */
+    pOpts->fOptSet &= ~OPTPROC_ERRSTOP;
+
+    /*
+     *  Find the last RC entry (highest priority entry)
+     */
+    for (idx = 0; pOpts->papzHomeList[ idx+1 ] != NULL; ++idx)  ;
+
+    /*
+     *  For every path in the home list, ...  *TWICE* We start at the last
+     *  (highest priority) entry, work our way down to the lowest priority,
+     *  handling the immediate options.
+     *  Then we go back up, doing the normal options.
+     */
+    for (;;) {
+        struct stat StatBuf;
+        cch_t*  pzPath;
+
+        /*
+         *  IF we've reached the bottom end, change direction
+         */
+        if (idx < 0) {
+            inc = DIRECTION_PROCESS;
+            idx = 0;
+        }
+
+        pzPath = pOpts->papzHomeList[ idx ];
+
+        /*
+         *  IF we've reached the top end, bail out
+         */
+        if (pzPath == NULL)
+            break;
+
+        idx += inc;
+
+        if (! optionMakePath(zFileName, (int)sizeof(zFileName),
+                             pzPath, pOpts->pzProgPath))
+            continue;
+
+        /*
+         *  IF the file name we constructed is a directory,
+         *  THEN append the Resource Configuration file name
+         *  ELSE we must have the complete file name
+         */
+        if (stat(zFileName, &StatBuf) != 0)
+            continue; /* bogus name - skip the home list entry */
+
+        if (S_ISDIR(StatBuf.st_mode)) {
+            size_t len = strlen(zFileName);
+            size_t nln = strlen(pOpts->pzRcName) + 1;
+            char * pz  = zFileName + len;
+
+            if (len + 1 + nln >= sizeof(zFileName))
+                continue;
+
+            if (pz[-1] != DIRCH)
+                *(pz++) = DIRCH;
+            memcpy(pz, pOpts->pzRcName, nln);
+        }
+
+        file_preset(pOpts, zFileName, inc);
+
+        /*
+         *  IF we are now to skip config files AND we are presetting,
+         *  THEN change direction.  We must go the other way.
+         */
+        {
+            tOptDesc * pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts+1;
+            if (DISABLED_OPT(pOD) && PRESETTING(inc)) {
+                idx -= inc;  /* go back and reprocess current file */
+                inc =  DIRECTION_PROCESS;
+            }
+        }
+    } /* twice for every path in the home list, ... */
+
+    pOpts->fOptSet = svfl;
+}
+
+
+/*=export_func optionFileLoad
+ *
+ * what: Load the locatable config files, in order
+ *
+ * arg:  + tOptions*   + pOpts  + program options descriptor +
+ * arg:  + char const* + pzProg + program name +
+ *
+ * ret_type:  int
+ * ret_desc:  0 -> SUCCESS, -1 -> FAILURE
+ *
+ * doc:
+ *
+ * This function looks in all the specified directories for a configuration
+ * file ("rc" file or "ini" file) and processes any found twice.  The first
+ * time through, they are processed in reverse order (last file first).  At
+ * that time, only "immediate action" configurables are processed.  For
+ * example, if the last named file specifies not processing any more
+ * configuration files, then no more configuration files will be processed.
+ * Such an option in the @strong{first} named directory will have no effect.
+ *
+ * Once the immediate action configurables have been handled, then the
+ * directories are handled in normal, forward order.  In that way, later
+ * config files can override the settings of earlier config files.
+ *
+ * See the AutoOpts documentation for a thorough discussion of the
+ * config file format.
+ *
+ * Configuration files not found or not decipherable are simply ignored.
+ *
+ * err:  Returns the value, "-1" if the program options descriptor
+ *       is out of date or indecipherable.  Otherwise, the value "0" will
+ *       always be returned.
+=*/
+int
+optionFileLoad(tOptions * pOpts, char const * pzProgram)
+{
+    if (! SUCCESSFUL(validate_struct(pOpts, pzProgram)))
+        return -1;
+
+    {
+        char const ** pp =
+            (char const **)(void *)&(pOpts->pzProgName);
+        *pp = pzProgram;
+    }
+
+    intern_file_load(pOpts);
+    return 0;
+}
+
+
+/*=export_func  optionLoadOpt
+ * private:
+ *
+ * what:  Load an option rc/ini file
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Processes the options found in the file named with
+ *  pOptDesc->optArg.argString.
+=*/
+void
+optionLoadOpt(tOptions * pOpts, tOptDesc * pOptDesc)
+{
+    struct stat sb;
+
+    /*
+     *  IF the option is not being disabled, THEN load the file.  There must
+     *  be a file.  (If it is being disabled, then the disablement processing
+     *  already took place.  It must be done to suppress preloading of ini/rc
+     *  files.)
+     */
+    if (  DISABLED_OPT(pOptDesc)
+       || ((pOptDesc->fOptState & OPTST_RESET) != 0))
+        return;
+
+    if (stat(pOptDesc->optArg.argString, &sb) != 0) {
+        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0)
+            return;
+
+        fprintf(stderr, zFSErrOptLoad, errno, strerror(errno),
+                pOptDesc->optArg.argString);
+        exit(EX_NOINPUT);
+        /* NOT REACHED */
+    }
+
+    if (! S_ISREG(sb.st_mode)) {
+        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0)
+            return;
+
+        fprintf(stderr, zNotFile, pOptDesc->optArg.argString);
+        exit(EX_NOINPUT);
+        /* NOT REACHED */
+    }
+
+    file_preset(pOpts, pOptDesc->optArg.argString, DIRECTION_CALLED);
+}
+
+
+/**
+ *  Parse the various attributes of an XML-styled config file entry
+ */
+LOCAL char*
+parseAttributes(
+    tOptions*           pOpts,
+    char*               pzText,
+    tOptionLoadMode*    pMode,
+    tOptionValue*       pType )
+{
+    size_t len;
+
+    do  {
+        if (! IS_WHITESPACE_CHAR(*pzText))
+            switch (*pzText) {
+            case '/': pType->valType = OPARG_TYPE_NONE;
+            case '>': return pzText;
+
+            default:
+            case NUL: return NULL;
+            }
+
+        while (IS_WHITESPACE_CHAR(*++pzText))     ;
+        len = 0;
+        while (IS_LOWER_CASE_CHAR(pzText[len]))   len++;
+
+        switch (find_xat_attribute_id(pzText, len)) {
+        case XAT_KWD_TYPE:
+            pzText = parse_value(pzText+len, pType);
+            break;
+
+        case XAT_KWD_WORDS:
+            pzText = parse_keyword(pOpts, pzText+len, pType);
+            break;
+
+        case XAT_KWD_MEMBERS:
+            pzText = parse_set_mem(pOpts, pzText+len, pType);
+            break;
+
+        case XAT_KWD_COOKED:
+            pzText += len;
+            if (! IS_END_XML_TOKEN_CHAR(*pzText))
+                goto invalid_kwd;
+
+            *pMode = OPTION_LOAD_COOKED;
+            break;
+
+        case XAT_KWD_UNCOOKED:
+            pzText += len;
+            if (! IS_END_XML_TOKEN_CHAR(*pzText))
+                goto invalid_kwd;
+
+            *pMode = OPTION_LOAD_UNCOOKED;
+            break;
+
+        case XAT_KWD_KEEP:
+            pzText += len;
+            if (! IS_END_XML_TOKEN_CHAR(*pzText))
+                goto invalid_kwd;
+
+            *pMode = OPTION_LOAD_KEEP;
+            break;
+
+        default:
+        case XAT_KWD_INVALID:
+        invalid_kwd:
+            pType->valType = OPARG_TYPE_NONE;
+            return skip_unkn(pzText);
+        }
+    } while (pzText != NULL);
+
+    return pzText;
+}
+
+
+/**
+ *  "pzText" points to the character after "words=".
+ *  What should follow is a name of a keyword (enumeration) list.
+ */
+static char*
+parse_keyword(tOptions * pOpts, char * pzText, tOptionValue * pType)
+{
+    return skip_unkn(pzText);
+}
+
+
+/**
+ *  "pzText" points to the character after "members="
+ *  What should follow is a name of a "set membership".
+ *  A collection of bit flags.
+ */
+static char*
+parse_set_mem(tOptions * pOpts, char * pzText, tOptionValue * pType)
+{
+    return skip_unkn(pzText);
+}
+
+
+/**
+ *  "pzText" points to the character after "type="
+ */
+static char *
+parse_value(char * pzText, tOptionValue * pType)
+{
+    size_t len = 0;
+
+    if (*(pzText++) != '=')
+        goto woops;
+
+    while (IS_OPTION_NAME_CHAR(pzText[len]))  len++;
+    pzText += len;
+
+    if ((len == 0) || (! IS_END_XML_TOKEN_CHAR(*pzText))) {
+    woops:
+        pType->valType = OPARG_TYPE_NONE;
+        return skip_unkn(pzText);
+    }
+
+    switch (find_value_type_id(pzText - len, len)) {
+    default:
+    case VTP_KWD_INVALID: goto woops;
+
+    case VTP_KWD_STRING:
+        pType->valType = OPARG_TYPE_STRING;
+        break;
+
+    case VTP_KWD_INTEGER:
+        pType->valType = OPARG_TYPE_NUMERIC;
+        break;
+
+    case VTP_KWD_BOOL:
+    case VTP_KWD_BOOLEAN:
+        pType->valType = OPARG_TYPE_BOOLEAN;
+        break;
+
+    case VTP_KWD_KEYWORD:
+        pType->valType = OPARG_TYPE_ENUMERATION;
+        break;
+
+    case VTP_KWD_SET:
+    case VTP_KWD_SET_MEMBERSHIP:
+        pType->valType = OPARG_TYPE_MEMBERSHIP;
+        break;
+
+    case VTP_KWD_NESTED:
+    case VTP_KWD_HIERARCHY:
+        pType->valType = OPARG_TYPE_HIERARCHY;
+    }
+
+    return pzText;
+}
+
+
+/**
+ *  Skip over some unknown attribute
+ */
+static char *
+skip_unkn(char* pzText)
+{
+    for (;; pzText++) {
+        if (IS_END_XML_TOKEN_CHAR(*pzText))  return pzText;
+        if (*pzText == NUL) return NULL;
+    }
+}
+
+
+/**
+ *  Make sure the option descriptor is there and that we understand it.
+ *  This should be called from any user entry point where one needs to
+ *  worry about validity.  (Some entry points are free to assume that
+ *  the call is not the first to the library and, thus, that this has
+ *  already been called.)
+ *
+ *  Upon successful completion, pzProgName and pzProgPath are set.
+ *
+ *  @param pOpts      program options descriptor
+ *  @param pzProgram  name of program, from argv[]
+ *  @returns SUCCESS or FAILURE
+ */
+LOCAL tSuccess
+validate_struct(tOptions * pOpts, char const * pzProgram)
+{
+    if (pOpts == NULL) {
+        fputs(zAO_Bad, stderr);
+        return FAILURE;
+    }
+
+    /*
+     *  IF the client has enabled translation and the translation procedure
+     *  is available, then go do it.
+     */
+    if (  ((pOpts->fOptSet & OPTPROC_TRANSLATE) != 0)
+       && (pOpts->pTransProc != NULL) ) {
+        /*
+         *  If option names are not to be translated at all, then do not do
+         *  it for configuration parsing either.  (That is the bit that really
+         *  gets tested anyway.)
+         */
+        if ((pOpts->fOptSet & OPTPROC_NO_XLAT_MASK) == OPTPROC_NXLAT_OPT)
+            pOpts->fOptSet |= OPTPROC_NXLAT_OPT_CFG;
+        (*pOpts->pTransProc)();
+        pOpts->fOptSet &= ~OPTPROC_TRANSLATE;
+    }
+
+    /*
+     *  IF the struct version is not the current, and also
+     *     either too large (?!) or too small,
+     *  THEN emit error message and fail-exit
+     */
+    if (  ( pOpts->structVersion  != OPTIONS_STRUCT_VERSION  )
+       && (  (pOpts->structVersion > OPTIONS_STRUCT_VERSION  )
+          || (pOpts->structVersion < OPTIONS_MINIMUM_VERSION )
+       )  )  {
+        static char const aover[] =
+            __STR(AO_CURRENT)":"__STR(AO_REVISION)":"__STR(AO_AGE)"\n";
+
+        fprintf(stderr, zAO_Err, pzProgram, NUM_TO_VER(pOpts->structVersion));
+        if (pOpts->structVersion > OPTIONS_STRUCT_VERSION )
+            fputs(zAO_Big, stderr);
+        else
+            fputs(zAO_Sml, stderr);
+
+        fwrite(aover, sizeof(aover) - 1, 1, stderr);
+        return FAILURE;
+    }
+
+    /*
+     *  If the program name hasn't been set, then set the name and the path
+     *  and the set of equivalent characters.
+     */
+    if (pOpts->pzProgName == NULL) {
+        char const *  pz = strrchr(pzProgram, DIRCH);
+        char const ** pp =
+            (char const **)(void **)&(pOpts->pzProgName);
+
+        if (pz != NULL) {
+            *pp = pz+1;
+        } else {
+            *pp = pzProgram;
+            pz = pathfind(getenv("PATH"), (char *)pzProgram, "rx");
+            if (pz != NULL)
+                pzProgram = (void *)pz;
+        }
+
+        pp  = (char const **)(void **)&(pOpts->pzProgPath);
+        *pp = pzProgram;
+
+        /*
+         *  when comparing long names, these are equivalent
+         */
+        strequate(zSepChars);
+    }
+
+    return SUCCESS;
+}
+
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/configfile.c */
diff --git a/libopts/cook.c b/libopts/cook.c
new file mode 100644 (file)
index 0000000..811ce59
--- /dev/null
@@ -0,0 +1,311 @@
+/**
+ * \file cook.c
+ *
+ *  Time-stamp:      "2011-03-12 15:05:26 bkorb"
+ *
+ *  This file contains the routines that deal with processing quoted strings
+ *  into an internal format.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static ag_bool
+contiguous_quote(char ** pps, char * pq, int * lnct_p);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*=export_func  ao_string_cook_escape_char
+ * private:
+ *
+ * what:  escape-process a string fragment
+ * arg:   + char const*  + pzScan  + points to character after the escape +
+ * arg:   + char*        + pRes    + Where to put the result byte +
+ * arg:   + unsigned int + nl_ch   + replacement char if scanned char is \n +
+ *
+ * ret-type: unsigned int
+ * ret-desc: The number of bytes consumed processing the escaped character.
+ *
+ * doc:
+ *
+ *  This function converts "t" into "\t" and all your other favorite
+ *  escapes, including numeric ones:  hex and ocatal, too.
+ *  The returned result tells the caller how far to advance the
+ *  scan pointer (passed in).  The default is to just pass through the
+ *  escaped character and advance the scan by one.
+ *
+ *  Some applications need to keep an escaped newline, others need to
+ *  suppress it.  This is accomplished by supplying a '\n' replacement
+ *  character that is different from \n, if need be.  For example, use
+ *  0x7F and never emit a 0x7F.
+ *
+ * err:  @code{NULL} is returned if the string is mal-formed.
+=*/
+unsigned int
+ao_string_cook_escape_char( char const* pzIn, char* pRes, u_int nl )
+{
+    unsigned int  res = 1;
+
+    switch (*pRes = *pzIn++) {
+    case NUL:         /* NUL - end of input string */
+        return 0;
+    case '\r':
+        if (*pzIn != '\n')
+            return 1;
+        res++;
+        /* FALLTHROUGH */
+    case '\n':        /* NL  - emit newline        */
+        *pRes = (char)nl;
+        return res;
+
+    case 'a': *pRes = '\a'; break;
+    case 'b': *pRes = '\b'; break;
+    case 'f': *pRes = '\f'; break;
+    case 'n': *pRes = '\n'; break;
+    case 'r': *pRes = '\r'; break;
+    case 't': *pRes = '\t'; break;
+    case 'v': *pRes = '\v'; break;
+
+    case 'x':
+    case 'X':         /* HEX Escape       */
+        if (IS_HEX_DIGIT_CHAR(*pzIn))  {
+            char z[4], *pz = z;
+
+            do *(pz++) = *(pzIn++);
+            while (IS_HEX_DIGIT_CHAR(*pzIn) && (pz < z + 2));
+            *pz = NUL;
+            *pRes = (unsigned char)strtoul(z, NULL, 16);
+            res += pz - z;
+        }
+        break;
+
+    case '0': case '1': case '2': case '3':
+    case '4': case '5': case '6': case '7':
+    {
+        /*
+         *  IF the character copied was an octal digit,
+         *  THEN set the output character to an octal value
+         */
+        char z[4], *pz = z + 1;
+        unsigned long val;
+        z[0] = *pRes;
+
+        while (IS_OCT_DIGIT_CHAR(*pzIn) && (pz < z + 3))
+            *(pz++) = *(pzIn++);
+        *pz = NUL;
+        val = strtoul(z, NULL, 8);
+        if (val > 0xFF)
+            val = 0xFF;
+        *pRes = (unsigned char)val;
+        res = pz - z;
+        break;
+    }
+
+    default: ;
+    }
+
+    return res;
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  A quoted string has been found.
+ *  Find the end of it and compress any escape sequences.
+ */
+static ag_bool
+contiguous_quote(char ** pps, char * pq, int * lnct_p)
+{
+    char * ps = *pps + 1;
+
+    for (;;) {
+        while (IS_WHITESPACE_CHAR(*ps))
+            if (*(ps++) == '\n')
+                (*lnct_p)++;
+
+        /*
+         *  IF the next character is a quote character,
+         *  THEN we will concatenate the strings.
+         */
+        switch (*ps) {
+        case '"':
+        case '\'':
+            *pq  = *(ps++);  /* assign new quote character and return */
+            *pps = ps;
+            return AG_TRUE;
+
+        case '/':
+            /*
+             *  Allow for a comment embedded in the concatenated string.
+             */
+            switch (ps[1]) {
+            default:
+                *pps = NULL;
+                return AG_FALSE;
+
+            case '/':
+                /*
+                 *  Skip to end of line
+                 */
+                ps = strchr(ps, '\n');
+                if (ps == NULL) {
+                    *pps = NULL;
+                    return AG_FALSE;
+                }
+                break;
+
+            case '*':
+            {
+                char* p = strstr( ps+2, "*/" );
+                /*
+                 *  Skip to terminating star slash
+                 */
+                if (p == NULL) {
+                    *pps = NULL;
+                    return AG_FALSE;
+                }
+
+                while (ps < p) {
+                    if (*(ps++) == '\n')
+                        (*lnct_p)++;
+                }
+
+                ps = p + 2;
+            }
+            }
+            continue;
+
+        default:
+            /*
+             *  The next non-whitespace character is not a quote.
+             *  The series of quoted strings has come to an end.
+             */
+            *pps = ps;
+            return AG_FALSE;
+        }
+    }
+}
+
+/*=export_func  ao_string_cook
+ * private:
+ *
+ * what:  concatenate and escape-process strings
+ * arg:   + char* + pzScan  + The *MODIFIABLE* input buffer +
+ * arg:   + int*  + lnct_p  + The (possibly NULL) pointer to a line count +
+ *
+ * ret-type: char*
+ * ret-desc: The address of the text following the processed strings.
+ *           The return value is NULL if the strings are ill-formed.
+ *
+ * doc:
+ *
+ *  A series of one or more quoted strings are concatenated together.
+ *  If they are quoted with double quotes (@code{"}), then backslash
+ *  escapes are processed per the C programming language.  If they are
+ *  single quote strings, then the backslashes are honored only when they
+ *  precede another backslash or a single quote character.
+ *
+ * err:  @code{NULL} is returned if the string(s) is/are mal-formed.
+=*/
+char *
+ao_string_cook(char * pzScan, int * lnct_p)
+{
+    int   l = 0;
+    char  q = *pzScan;
+
+    /*
+     *  It is a quoted string.  Process the escape sequence characters
+     *  (in the set "abfnrtv") and make sure we find a closing quote.
+     */
+    char* pzD = pzScan++;
+    char* pzS = pzScan;
+
+    if (lnct_p == NULL)
+        lnct_p = &l;
+
+    for (;;) {
+        /*
+         *  IF the next character is the quote character, THEN we may end the
+         *  string.  We end it unless the next non-blank character *after* the
+         *  string happens to also be a quote.  If it is, then we will change
+         *  our quote character to the new quote character and continue
+         *  condensing text.
+         */
+        while (*pzS == q) {
+            *pzD = NUL; /* This is probably the end of the line */
+            if (! contiguous_quote(&pzS, &q, lnct_p))
+                return pzS;
+        }
+
+        /*
+         *  We are inside a quoted string.  Copy text.
+         */
+        switch (*(pzD++) = *(pzS++)) {
+        case NUL:
+            return NULL;
+
+        case '\n':
+            (*lnct_p)++;
+            break;
+
+        case '\\':
+            /*
+             *  IF we are escaping a new line,
+             *  THEN drop both the escape and the newline from
+             *       the result string.
+             */
+            if (*pzS == '\n') {
+                pzS++;
+                pzD--;
+                (*lnct_p)++;
+            }
+
+            /*
+             *  ELSE IF the quote character is '"' or '`',
+             *  THEN we do the full escape character processing
+             */
+            else if (q != '\'') {
+                int ct = ao_string_cook_escape_char( pzS, pzD-1, (u_int)'\n' );
+                if (ct == 0)
+                    return NULL;
+
+                pzS += ct;
+            }     /* if (q != '\'')                  */
+
+            /*
+             *  OTHERWISE, we only process "\\", "\'" and "\#" sequences.
+             *  The latter only to easily hide preprocessing directives.
+             */
+            else switch (*pzS) {
+            case '\\':
+            case '\'':
+            case '#':
+                pzD[-1] = *pzS++;
+            }
+        }     /* switch (*(pzD++) = *(pzS++))    */
+    }         /* for (;;)                        */
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/cook.c */
diff --git a/libopts/enum.c b/libopts/enum.c
new file mode 100644 (file)
index 0000000..a79a32e
--- /dev/null
@@ -0,0 +1,522 @@
+
+/**
+ * \file enumeration.c
+ *
+ * Time-stamp:      "2011-04-06 10:48:22 bkorb"
+ *
+ *   Automated Options Paged Usage module.
+ *
+ *  This routine will run run-on options through a pager so the
+ *  user may examine, print or edit them at their leisure.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+static char const * pz_enum_err_fmt;
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+enum_err(tOptions * pOpts, tOptDesc * pOD,
+         char const * const * paz_names, int name_ct);
+
+static uintptr_t
+find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD,
+          char const * const *  paz_names, unsigned int name_ct);
+
+static void
+set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct);
+
+static void
+set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct);
+
+static void
+set_memb_names(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct);
+/* = = = END-STATIC-FORWARD = = = */
+
+static void
+enum_err(tOptions * pOpts, tOptDesc * pOD,
+         char const * const * paz_names, int name_ct)
+{
+    size_t max_len = 0;
+    size_t ttl_len = 0;
+    int    ct_down = name_ct;
+    int    hidden  = 0;
+
+    /*
+     *  A real "pOpts" pointer means someone messed up.  Give a real error.
+     */
+    if (pOpts > OPTPROC_EMIT_LIMIT)
+        fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
+                pOD->optArg.argString, pOD->pz_Name);
+
+    fprintf(option_usage_fp, zValidKeys, pOD->pz_Name);
+
+    /*
+     *  If the first name starts with this funny character, then we have
+     *  a first value with an unspellable name.  You cannot specify it.
+     *  So, we don't list it either.
+     */
+    if (**paz_names == 0x7F) {
+        paz_names++;
+        hidden  = 1;
+        ct_down = --name_ct;
+    }
+
+    /*
+     *  Figure out the maximum length of any name, plus the total length
+     *  of all the names.
+     */
+    {
+        char const * const * paz = paz_names;
+
+        do  {
+            size_t len = strlen(*(paz++)) + 1;
+            if (len > max_len)
+                max_len = len;
+            ttl_len += len;
+        } while (--ct_down > 0);
+
+        ct_down = name_ct;
+    }
+
+    /*
+     *  IF any one entry is about 1/2 line or longer, print one per line
+     */
+    if (max_len > 35) {
+        do  {
+            fprintf(option_usage_fp, "  %s\n", *(paz_names++));
+        } while (--ct_down > 0);
+    }
+
+    /*
+     *  ELSE IF they all fit on one line, then do so.
+     */
+    else if (ttl_len < 76) {
+        fputc(' ', option_usage_fp);
+        do  {
+            fputc(' ', option_usage_fp);
+            fputs(*(paz_names++), option_usage_fp);
+        } while (--ct_down > 0);
+        fputc('\n', option_usage_fp);
+    }
+
+    /*
+     *  Otherwise, columnize the output
+     */
+    else {
+        int   ent_no = 0;
+        char  zFmt[16];  /* format for all-but-last entries on a line */
+
+        sprintf(zFmt, "%%-%ds", (int)max_len);
+        max_len = 78 / max_len; /* max_len is now max entries on a line */
+        fputs("  ", option_usage_fp);
+
+        /*
+         *  Loop through all but the last entry
+         */
+        ct_down = name_ct;
+        while (--ct_down > 0) {
+            if (++ent_no == max_len) {
+                /*
+                 *  Last entry on a line.  Start next line, too.
+                 */
+                fprintf(option_usage_fp, "%s\n  ", *(paz_names++));
+                ent_no = 0;
+            }
+
+            else
+                fprintf(option_usage_fp, zFmt, *(paz_names++) );
+        }
+        fprintf(option_usage_fp, "%s\n", *paz_names);
+    }
+
+    if (pOpts > OPTPROC_EMIT_LIMIT) {
+        fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
+
+        (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+    }
+
+    if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
+        fprintf(option_usage_fp, zLowerBits, name_ct);
+        fputs(zSetMemberSettings, option_usage_fp);
+    } else {
+        fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
+    }
+}
+
+
+static uintptr_t
+find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD,
+          char const * const *  paz_names, unsigned int name_ct)
+{
+    /*
+     *  Return the matching index as a pointer sized integer.
+     *  The result gets stashed in a char* pointer.
+     */
+    uintptr_t   res = name_ct;
+    size_t      len = strlen((char*)pzName);
+    uintptr_t   idx;
+
+    if (IS_DEC_DIGIT_CHAR(*pzName)) {
+        char * pz = (char *)(void *)pzName;
+        unsigned long val = strtoul(pz, &pz, 0);
+        if ((*pz == NUL) && (val < name_ct))
+            return (uintptr_t)val;
+        enum_err(pOpts, pOD, paz_names, (int)name_ct);
+        return name_ct;
+    }
+
+    /*
+     *  Look for an exact match, but remember any partial matches.
+     *  Multiple partial matches means we have an ambiguous match.
+     */
+    for (idx = 0; idx < name_ct; idx++) {
+        if (strncmp((char*)paz_names[idx], (char*)pzName, len) == 0) {
+            if (paz_names[idx][len] == NUL)
+                return idx;  /* full match */
+
+            res = (res != name_ct) ? ~0 : idx; /* save partial match */
+        }
+    }
+
+    if (res < name_ct)
+        return res; /* partial match */
+
+    pz_enum_err_fmt = (res == name_ct) ? zNoKey : zAmbigKey;
+    option_usage_fp = stderr;
+    enum_err(pOpts, pOD, paz_names, (int)name_ct);
+    return name_ct;
+}
+
+
+/*=export_func  optionKeywordName
+ * what:  Convert between enumeration values and strings
+ * private:
+ *
+ * arg:   tOptDesc*,     pOD,       enumeration option description
+ * arg:   unsigned int,  enum_val,  the enumeration value to map
+ *
+ * ret_type:  char const *
+ * ret_desc:  the enumeration name from const memory
+ *
+ * doc:   This converts an enumeration value into the matching string.
+=*/
+char const *
+optionKeywordName(tOptDesc * pOD, unsigned int enum_val)
+{
+    tOptDesc od;
+
+    od.optArg.argEnum = enum_val;
+    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od );
+    return od.optArg.argString;
+}
+
+
+/*=export_func  optionEnumerationVal
+ * what:  Convert from a string to an enumeration value
+ * private:
+ *
+ * arg:   tOptions*,     pOpts,     the program options descriptor
+ * arg:   tOptDesc*,     pOD,       enumeration option description
+ * arg:   char const * const *,  paz_names, list of enumeration names
+ * arg:   unsigned int,  name_ct,   number of names in list
+ *
+ * ret_type:  uintptr_t
+ * ret_desc:  the enumeration value
+ *
+ * doc:   This converts the optArg.argString string from the option description
+ *        into the index corresponding to an entry in the name list.
+ *        This will match the generated enumeration value.
+ *        Full matches are always accepted.  Partial matches are accepted
+ *        if there is only one partial match.
+=*/
+uintptr_t
+optionEnumerationVal(tOptions * pOpts, tOptDesc * pOD,
+                     char const * const * paz_names, unsigned int name_ct)
+{
+    uintptr_t res = 0UL;
+
+    /*
+     *  IF the program option descriptor pointer is invalid,
+     *  then it is some sort of special request.
+     */
+    switch ((uintptr_t)pOpts) {
+    case (uintptr_t)OPTPROC_EMIT_USAGE:
+        /*
+         *  print the list of enumeration names.
+         */
+        enum_err(pOpts, pOD, paz_names, (int)name_ct);
+        break;
+
+    case (uintptr_t)OPTPROC_EMIT_SHELL:
+    {
+        unsigned int ix = pOD->optArg.argEnum;
+        /*
+         *  print the name string.
+         */
+        if (ix >= name_ct)
+            printf("INVALID-%d", ix);
+        else
+            fputs(paz_names[ ix ], stdout);
+
+        break;
+    }
+
+    case (uintptr_t)OPTPROC_RETURN_VALNAME:
+    {
+        tSCC zInval[] = "*INVALID*";
+        unsigned int ix = pOD->optArg.argEnum;
+        /*
+         *  Replace the enumeration value with the name string.
+         */
+        if (ix >= name_ct)
+            return (uintptr_t)zInval;
+
+        pOD->optArg.argString = paz_names[ix];
+        break;
+    }
+
+    default:
+        res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct);
+
+        if (pOD->fOptState & OPTST_ALLOC_ARG) {
+            AGFREE(pOD->optArg.argString);
+            pOD->fOptState &= ~OPTST_ALLOC_ARG;
+            pOD->optArg.argString = NULL;
+        }
+    }
+
+    return res;
+}
+
+static void
+set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct)
+{
+    /*
+     *  print the list of enumeration names.
+     */
+    enum_err(OPTPROC_EMIT_USAGE, pOD, paz_names, (int)name_ct );
+}
+
+static void
+set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct)
+{
+    /*
+     *  print the name string.
+     */
+    int       ix   =  0;
+    uintptr_t bits = (uintptr_t)pOD->optCookie;
+    size_t    len  = 0;
+
+    bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
+
+    while (bits != 0) {
+        if (bits & 1) {
+            if (len++ > 0) fputs(" | ", stdout);
+            fputs(paz_names[ix], stdout);
+        }
+        if (++ix >= name_ct) break;
+        bits >>= 1;
+    }
+}
+
+static void
+set_memb_names(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
+               unsigned int name_ct)
+{
+    static char const none[]  = "none";
+    static char const plus[3] = " + ";
+
+    char *    pz;
+    uintptr_t bits = (uintptr_t)pOD->optCookie;
+    int       ix   = 0;
+    size_t    len  = sizeof(none);
+
+    bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
+
+    /*
+     *  Replace the enumeration value with the name string.
+     *  First, determine the needed length, then allocate and fill in.
+     */
+    while (bits != 0) {
+        if (bits & 1)
+            len += strlen(paz_names[ix]) + sizeof(plus);
+        if (++ix >= name_ct) break;
+        bits >>= 1;
+    }
+
+    pOD->optArg.argString = pz = AGALOC(len, "enum name");
+
+    /*
+     *  Start by clearing all the bits.  We want to turn off any defaults
+     *  because we will be restoring to current state, not adding to
+     *  the default set of bits.
+     */
+    memcpy(pz, none, sizeof(none)-1);
+    pz += sizeof(none)-1;
+    bits = (uintptr_t)pOD->optCookie;
+    bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
+    ix = 0;
+
+    while (bits != 0) {
+        if (bits & 1) {
+            size_t nln = strlen(paz_names[ix]);
+            memcpy(pz, plus, sizeof(plus));
+            memcpy(pz+sizeof(plus), paz_names[ix], nln);
+            pz += strlen(paz_names[ix]) + 3;
+        }
+        if (++ix >= name_ct) break;
+        bits >>= 1;
+    }
+    *pz = NUL;
+}
+
+/*=export_func  optionSetMembers
+ * what:  Convert between bit flag values and strings
+ * private:
+ *
+ * arg:   tOptions*,     pOpts,     the program options descriptor
+ * arg:   tOptDesc*,     pOD,       enumeration option description
+ * arg:   char const * const *,
+ *                       paz_names, list of enumeration names
+ * arg:   unsigned int,  name_ct,   number of names in list
+ *
+ * doc:   This converts the optArg.argString string from the option description
+ *        into the index corresponding to an entry in the name list.
+ *        This will match the generated enumeration value.
+ *        Full matches are always accepted.  Partial matches are accepted
+ *        if there is only one partial match.
+=*/
+void
+optionSetMembers(tOptions * pOpts, tOptDesc * pOD,
+                 char const* const * paz_names, unsigned int name_ct)
+{
+    /*
+     *  IF the program option descriptor pointer is invalid,
+     *  then it is some sort of special request.
+     */
+    switch ((uintptr_t)pOpts) {
+    case (uintptr_t)OPTPROC_EMIT_USAGE:
+        set_memb_usage(pOpts, pOD, paz_names, name_ct);
+        return;
+
+    case (uintptr_t)OPTPROC_EMIT_SHELL:
+        set_memb_shell(pOpts, pOD, paz_names, name_ct);
+        return;
+
+    case (uintptr_t)OPTPROC_RETURN_VALNAME:
+        set_memb_names(pOpts, pOD, paz_names, name_ct);
+        return;
+
+    default:
+        break;
+    }
+
+    if ((pOD->fOptState & OPTST_RESET) != 0)
+        return;
+
+    {
+        char const*      pzArg = pOD->optArg.argString;
+        uintptr_t res;
+        if ((pzArg == NULL) || (*pzArg == NUL)) {
+            pOD->optCookie = (void*)0;
+            return;
+        }
+
+        res = (uintptr_t)pOD->optCookie;
+        for (;;) {
+            tSCC zSpn[] = " ,|+\t\r\f\n";
+            int  iv, len;
+
+            pzArg += strspn(pzArg, zSpn);
+            iv = (*pzArg == '!');
+            if (iv)
+                pzArg += strspn(pzArg+1, zSpn) + 1;
+
+            len = strcspn(pzArg, zSpn);
+            if (len == 0)
+                break;
+
+            if ((len == 3) && (strncmp(pzArg, zAll, 3) == 0)) {
+                if (iv)
+                     res = 0;
+                else res = ~0UL;
+            }
+            else if ((len == 4) && (strncmp(pzArg, zNone, 4) == 0)) {
+                if (! iv)
+                    res = 0;
+            }
+            else do {
+                char* pz;
+                uintptr_t bit = strtoul(pzArg, &pz, 0);
+
+                if (pz != pzArg + len) {
+                    char z[ AO_NAME_SIZE ];
+                    char const* p;
+                    int  shift_ct;
+
+                    if (*pz != NUL) {
+                        if (len >= AO_NAME_LIMIT)
+                            break;
+                        memcpy(z, pzArg, (size_t)len);
+                        z[len] = NUL;
+                        p = z;
+                    } else {
+                        p = pzArg;
+                    }
+
+                    shift_ct = find_name(p, pOpts, pOD, paz_names, name_ct);
+                    if (shift_ct >= name_ct) {
+                        pOD->optCookie = (void*)0;
+                        return;
+                    }
+                    bit = 1UL << shift_ct;
+                }
+                if (iv)
+                     res &= ~bit;
+                else res |= bit;
+            } while (0);
+
+            if (pzArg[len] == NUL)
+                break;
+            pzArg += len + 1;
+        }
+        if (name_ct < (8 * sizeof(uintptr_t))) {
+            res &= (1UL << name_ct) - 1UL;
+        }
+
+        pOD->optCookie = (void*)res;
+    }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/enumeration.c */
diff --git a/libopts/env.c b/libopts/env.c
new file mode 100644 (file)
index 0000000..c8e9154
--- /dev/null
@@ -0,0 +1,259 @@
+
+/**
+ * \file environment.c
+ *
+ * Time-stamp:      "2011-07-19 17:43:34 bkorb"
+ *
+ *  This file contains all of the routines that must be linked into
+ *  an executable to use the generated option processing.  The optional
+ *  routines are in separately compiled modules so that they will not
+ *  necessarily be linked in.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+do_env_opt(tOptState * os, char * env_name,
+            tOptions * pOpts, teEnvPresetType type);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*
+ *  doPrognameEnv - check for preset values from the ${PROGNAME}
+ *  environment variable.  This is accomplished by parsing the text into
+ *  tokens, temporarily replacing the arg vector and calling
+ *  immediate_opts and/or regular_opts.
+ */
+LOCAL void
+doPrognameEnv(tOptions * pOpts, teEnvPresetType type)
+{
+    char const*   pczOptStr = getenv(pOpts->pzPROGNAME);
+    token_list_t* pTL;
+    int           sv_argc;
+    tAoUI         sv_flag;
+    char**        sv_argv;
+
+    /*
+     *  No such beast?  Then bail now.
+     */
+    if (pczOptStr == NULL)
+        return;
+
+    /*
+     *  Tokenize the string.  If there's nothing of interest, we'll bail
+     *  here immediately.
+     */
+    pTL = ao_string_tokenize(pczOptStr);
+    if (pTL == NULL)
+        return;
+
+    /*
+     *  Substitute our $PROGNAME argument list for the real one
+     */
+    sv_argc = pOpts->origArgCt;
+    sv_argv = pOpts->origArgVect;
+    sv_flag = pOpts->fOptSet;
+
+    /*
+     *  We add a bogus pointer to the start of the list.  The program name
+     *  has already been pulled from "argv", so it won't get dereferenced.
+     *  The option scanning code will skip the "program name" at the start
+     *  of this list of tokens, so we accommodate this way ....
+     */
+    pOpts->origArgVect = (char**)(pTL->tkn_list - 1);
+    pOpts->origArgCt   = pTL->tkn_ct   + 1;
+    pOpts->fOptSet    &= ~OPTPROC_ERRSTOP;
+
+    pOpts->curOptIdx   = 1;
+    pOpts->pzCurOpt    = NULL;
+
+    switch (type) {
+    case ENV_IMM:
+        (void)immediate_opts(pOpts);
+        break;
+
+    case ENV_ALL:
+        (void)immediate_opts(pOpts);
+        pOpts->curOptIdx = 1;
+        pOpts->pzCurOpt  = NULL;
+        /* FALLTHROUGH */
+
+    case ENV_NON_IMM:
+        (void)regular_opts(pOpts);
+    }
+
+    /*
+     *  Free up the temporary arg vector and restore the original program args.
+     */
+    free(pTL);
+    pOpts->origArgVect = sv_argv;
+    pOpts->origArgCt   = sv_argc;
+    pOpts->fOptSet     = sv_flag;
+}
+
+static void
+do_env_opt(tOptState * os, char * env_name,
+            tOptions * pOpts, teEnvPresetType type)
+{
+    os->pzOptArg = getenv(env_name);
+    if (os->pzOptArg == NULL)
+        return;
+
+    os->flags   = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState;
+    os->optType = TOPT_UNDEFINED;
+
+    if (  (os->pOD->pz_DisablePfx != NULL)
+       && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) {
+        os->flags |= OPTST_DISABLED;
+        os->pzOptArg = NULL;
+    }
+
+    switch (type) {
+    case ENV_IMM:
+        /*
+         *  Process only immediate actions
+         */
+        if (DO_IMMEDIATELY(os->flags))
+            break;
+        return;
+
+    case ENV_NON_IMM:
+        /*
+         *  Process only NON immediate actions
+         */
+        if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags))
+            break;
+        return;
+
+    default: /* process everything */
+        break;
+    }
+
+    /*
+     *  Make sure the option value string is persistent and consistent.
+     *
+     *  The interpretation of the option value depends
+     *  on the type of value argument the option takes
+     */
+    if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) {
+        /*
+         *  Ignore any value.
+         */
+        os->pzOptArg = NULL;
+
+    } else if (os->pzOptArg[0] == NUL) {
+        /*
+         * If the argument is the empty string and the argument is
+         * optional, then treat it as if the option was not specified.
+         */
+        if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0)
+            return;
+        os->pzOptArg = NULL;
+
+    } else {
+        AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument");
+        os->flags |= OPTST_ALLOC_ARG;
+    }
+
+    handle_opt(pOpts, os);
+}
+
+/*
+ *  env_presets - check for preset values from the envrionment
+ *  This routine should process in all, immediate or normal modes....
+ */
+LOCAL void
+env_presets(tOptions * pOpts, teEnvPresetType type)
+{
+    int        ct;
+    tOptState  st;
+    char*      pzFlagName;
+    size_t     spaceLeft;
+    char       zEnvName[ AO_NAME_SIZE ];
+
+    /*
+     *  Finally, see if we are to look at the environment
+     *  variables for initial values.
+     */
+    if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0)
+        return;
+
+    doPrognameEnv(pOpts, type);
+
+    ct  = pOpts->presetOptCt;
+    st.pOD = pOpts->pOptDesc;
+
+    pzFlagName = zEnvName
+        + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME);
+    spaceLeft = AO_NAME_SIZE - (pzFlagName - zEnvName) - 1;
+
+    for (;ct-- > 0; st.pOD++) {
+        size_t nln;
+
+        /*
+         *  If presetting is disallowed, then skip this entry
+         */
+        if (  ((st.pOD->fOptState & OPTST_NO_INIT) != 0)
+           || (st.pOD->optEquivIndex != NO_EQUIVALENT)  )
+            continue;
+
+        /*
+         *  IF there is no such environment variable,
+         *  THEN skip this entry, too.
+         */
+        nln = strlen(st.pOD->pz_NAME) + 1;
+        if (nln <= spaceLeft) {
+            /*
+             *  Set up the option state
+             */
+            memcpy(pzFlagName, st.pOD->pz_NAME, nln);
+            do_env_opt(&st, zEnvName, pOpts, type);
+        }
+    }
+
+    /*
+     *  Special handling for ${PROGNAME_LOAD_OPTS}
+     */
+    if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
+       && (pOpts->specOptIdx.save_opts != 0)) {
+        size_t nln;
+        st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
+
+        if (st.pOD->pz_NAME == NULL)
+            return;
+
+        nln = strlen(st.pOD->pz_NAME) + 1;
+            
+        if (nln > spaceLeft)
+            return;
+
+        memcpy(pzFlagName, st.pOD->pz_NAME, nln);
+        do_env_opt(&st, zEnvName, pOpts, type);
+    }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/environment.c */
diff --git a/libopts/file.c b/libopts/file.c
new file mode 100644 (file)
index 0000000..2399474
--- /dev/null
@@ -0,0 +1,208 @@
+
+/**
+ * \file file.c
+ *
+ *  Time-stamp:      "2011-08-06 08:49:35 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/**
+ *  Make sure the directory containing the subject file exists and that
+ *  the file exists or does not exist, per the option requirements.
+ *
+ * @param ftype file existence type flags
+ * @param pOpts program option descriptor
+ * @param pOD   the option descriptor
+ */
+static void
+check_existence(teOptFileType ftype, tOptions * pOpts, tOptDesc * pOD)
+{
+    char const * fname = pOD->optArg.argString;
+    struct stat sb;
+
+    errno = 0;
+
+    switch (ftype & FTYPE_MODE_EXIST_MASK) {
+    case FTYPE_MODE_MUST_NOT_EXIST:
+        if ((stat(fname, &sb) == 0) || (errno != ENOENT)) {
+            if (errno == 0)
+                errno = EINVAL;
+            fprintf(stderr, zFSOptError, errno, strerror(errno),
+                    zFSOptErrNoExist, fname, pOD->pz_Name);
+            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+        }
+        /* FALLTHROUGH */
+
+    default:
+    case FTYPE_MODE_MAY_EXIST:
+    {
+        char * p = strrchr(fname, DIRCH);
+        size_t l;
+
+        if (p == NULL)
+            /*
+             *  The file may or may not exist and its directory is ".".
+             *  Assume that "." exists.
+             */
+            break;
+
+        l = p - fname;
+        p = AGALOC(l + 1, "fname");
+        memcpy(p, fname, l);
+        p[l] = NUL;
+
+        if ((stat(p, &sb) != 0) || (errno = EINVAL, ! S_ISDIR(sb.st_mode))) {
+            fprintf(stderr, zFSOptError, errno, strerror(errno),
+                    zFSOptErrMayExist, fname, pOD->pz_Name);
+            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+        }
+        AGFREE(p);
+        break;
+    }
+
+    case FTYPE_MODE_MUST_EXIST:
+        if (  (stat(fname, &sb) != 0)
+           || (errno = EINVAL, ! S_ISREG(sb.st_mode)) ) {
+            fprintf(stderr, zFSOptError, errno, strerror(errno),
+                    zFSOptErrMustExist, fname,
+                    pOD->pz_Name);
+            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+        }
+        break;
+    }
+}
+
+/**
+ *  Open the specified file with open(2) and save the FD.
+ *
+ * @param pOpts program option descriptor
+ * @param pOD   the option descriptor
+ * @param mode  the open mode (uses int flags value)
+ */
+static void
+open_file_fd(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode)
+{
+    int fd = open(pOD->optArg.argString, mode.file_flags);
+    if (fd < 0) {
+        fprintf(stderr, zFSOptError, errno, strerror(errno),
+                zFSOptErrOpen, pOD->optArg.argString, pOD->pz_Name);
+        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+    }
+
+    if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0)
+        pOD->optCookie = (void *)pOD->optArg.argString;
+    else
+        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");
+
+    pOD->optArg.argFd = fd;
+    pOD->fOptState &= ~OPTST_ALLOC_ARG;
+}
+
+/**
+ *  Open the specified file with open(2) and save the FD.
+ *
+ * @param pOpts program option descriptor
+ * @param pOD   the option descriptor
+ * @param mode  the open mode (uses "char *" mode value)
+ */
+static void
+fopen_file_fp(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode)
+{
+    FILE* fp = fopen(pOD->optArg.argString, mode.file_mode);
+    if (fp == NULL) {
+        fprintf(stderr, zFSOptError, errno, strerror(errno),
+                zFSOptErrFopen, pOD->optArg.argString, pOD->pz_Name);
+        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+    }
+
+    if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0)
+        pOD->optCookie = (void *)pOD->optArg.argString;
+    else
+        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");
+
+    pOD->optArg.argFp = fp;
+    pOD->fOptState &= ~OPTST_ALLOC_ARG;
+}
+
+/*=export_func  optionFileCheck
+ * private:
+ *
+ * what:  Decipher a boolean value
+ * arg:   + tOptions*     + pOpts    + program options descriptor  +
+ * arg:   + tOptDesc*     + pOptDesc + the descriptor for this arg +
+ * arg:   + teOptFileType + ftype    + File handling type          +
+ * arg:   + tuFileMode    + mode     + file open mode (if needed)  +
+ *
+ * doc:
+ *   Make sure the named file conforms with the file type mode.
+ *   The mode specifies if the file must exist, must not exist or may
+ *   (or may not) exist.  The mode may also specify opening the
+ *   file: don't, open just the descriptor (fd), or open as a stream
+ *   (FILE* pointer).
+=*/
+void
+optionFileCheck(tOptions * pOpts, tOptDesc * pOD,
+                teOptFileType ftype, tuFileMode mode)
+{
+    if (pOpts <= OPTPROC_EMIT_LIMIT) {
+        if (pOpts != OPTPROC_EMIT_USAGE)
+            return;
+
+        switch (ftype & FTYPE_MODE_EXIST_MASK) {
+        case FTYPE_MODE_MUST_NOT_EXIST:
+            fputs(zFileCannotExist, option_usage_fp);
+            break;
+
+        case FTYPE_MODE_MUST_EXIST:
+            fputs(zFileMustExist, option_usage_fp);
+            break;
+        }
+        return;
+    }
+
+    if ((pOD->fOptState & OPTST_RESET) != 0) {
+        if (pOD->optCookie != NULL)
+            AGFREE(pOD->optCookie);
+        return;
+    }
+
+    check_existence(ftype, pOpts, pOD);
+
+    switch (ftype & FTYPE_MODE_OPEN_MASK) {
+    default:
+    case FTYPE_MODE_NO_OPEN:  break;
+    case FTYPE_MODE_OPEN_FD:  open_file_fd( pOpts, pOD, mode); break;
+    case FTYPE_MODE_FOPEN_FP: fopen_file_fp(pOpts, pOD, mode); break;
+    }
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/file.c */
diff --git a/libopts/find.c b/libopts/find.c
new file mode 100644 (file)
index 0000000..7a9ba17
--- /dev/null
@@ -0,0 +1,568 @@
+/**
+ * @file check.c
+ *
+ * @brief Hunt for options in the option descriptor list
+ *
+ *  Time-stamp:      "2011-08-07 13:15:45 bkorb"
+ *
+ *  This file contains the routines that deal with processing quoted strings
+ *  into an internal format.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/**
+ * find the name and name length we are looking for
+ */
+static int
+parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz)
+{
+    int  res = 0;
+    char const * p = *nm_pp;
+    *arg_pp  = NULL;
+
+    for (;;) {
+        switch (*(p++)) {
+        case NUL: return res;
+
+        case '=':
+            if (res >= bufsz)
+                return -1;
+
+            memcpy(buf, *nm_pp, res);
+
+            buf[res] = NUL;
+            *nm_pp   = buf;
+            *arg_pp  = (char *)p;
+            return res;
+
+        default:
+            res++;
+        }
+    }
+}
+
+/**
+ *  print out the options that match the given name.
+ *
+ * @param pOpts      option data
+ * @param opt_name   name of option to look for
+ */
+static void
+opt_ambiguities(tOptions * opts, char const * name, int nm_len)
+{
+    char const * const hyph =
+        NAMED_OPTS(opts) ? "" : "--";
+
+    tOptDesc * pOD = opts->pOptDesc;
+    int        idx = 0;
+
+    fputs(zAmbigList, stderr);
+    do  {
+        if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0)
+            fprintf(stderr, zAmbiguous, hyph, pOD->pz_Name);
+
+        else if (  (pOD->pz_DisableName != NULL)
+                && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
+                )
+            fprintf(stderr, zAmbiguous, hyph, pOD->pz_DisableName);
+    } while (pOD++, (++idx < opts->optCt));
+}
+
+/**
+ *  Determine the number of options that match the name
+ *
+ * @param pOpts      option data
+ * @param opt_name   name of option to look for
+ * @param nm_len     length of provided name
+ * @param index      pointer to int for option index
+ * @param disable    pointer to bool to mark disabled option
+ * @return count of options that match
+ */
+static int
+opt_match_ct(tOptions * opts, char const * name, int nm_len,
+             int * ixp, ag_bool * disable)
+{
+    int   matchCt  = 0;
+    int   idx      = 0;
+    int   idxLim   = opts->optCt;
+    tOptDesc * pOD = opts->pOptDesc;
+
+    do  {
+        /*
+         *  If option disabled or a doc option, skip to next
+         */
+        if (pOD->pz_Name == NULL)
+            continue;
+
+        if (  SKIP_OPT(pOD)
+           && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT)))
+            continue;
+
+        if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) {
+            /*
+             *  IF we have a complete match
+             *  THEN it takes priority over any already located partial
+             */
+            if (pOD->pz_Name[ nm_len ] == NUL) {
+                *ixp = idx;
+                return 1;
+            }
+        }
+
+        /*
+         *  IF       there is a disable name
+         *     *AND* the option name matches the disable name
+         *  THEN ...
+         */
+        else if (  (pOD->pz_DisableName != NULL)
+                && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
+                )  {
+            *disable = AG_TRUE;
+
+            /*
+             *  IF we have a complete match
+             *  THEN it takes priority over any already located partial
+             */
+            if (pOD->pz_DisableName[ nm_len ] == NUL) {
+                *ixp = idx;
+                return 1;
+            }
+        }
+
+        else
+            continue; /* does not match any option */
+
+        /*
+         *  We found a full or partial match, either regular or disabling.
+         *  Remember the index for later.
+         */
+        *ixp = idx;
+        ++matchCt;
+
+    } while (pOD++, (++idx < idxLim));
+
+    return matchCt;
+}
+
+/**
+ *  Set the option to the indicated option number.
+ *
+ * @param opts      option data
+ * @param arg       option argument (if glued to name)
+ * @param idx       option index
+ * @param disable   mark disabled option
+ * @param st        state about current option
+ */
+static tSuccess
+opt_set(tOptions * opts, char * arg, int idx, ag_bool disable, tOptState * st)
+{
+    tOptDesc * pOD = opts->pOptDesc + idx;
+
+    if (SKIP_OPT(pOD)) {
+        if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
+            return FAILURE;
+
+        fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name);
+        if (pOD->pzText != NULL)
+            fprintf(stderr, " -- %s", pOD->pzText);
+        fputc('\n', stderr);
+        (*opts->pUsageProc)(opts, EXIT_FAILURE);
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE); /* to be certain */
+    }
+
+    /*
+     *  IF we found a disablement name,
+     *  THEN set the bit in the callers' flag word
+     */
+    if (disable)
+        st->flags |= OPTST_DISABLED;
+
+    st->pOD      = pOD;
+    st->pzOptArg = arg;
+    st->optType  = TOPT_LONG;
+
+    return SUCCESS;
+}
+
+/**
+ *  An option was not found.  Check for default option and set it
+ *  if there is one.  Otherwise, handle the error.
+ *
+ * @param opts   option data
+ * @param name   name of option to look for
+ * @param arg    option argument
+ * @param st     state about current option
+ *
+ * @return success status
+ */
+static tSuccess
+opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st)
+{
+    /*
+     *  IF there is no equal sign
+     *     *AND* we are using named arguments
+     *     *AND* there is a default named option,
+     *  THEN return that option.
+     */
+    if (  (arg == NULL)
+       && NAMED_OPTS(opts)
+       && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) {
+
+        st->pOD      = opts->pOptDesc + opts->specOptIdx.default_opt;
+        st->pzOptArg = name;
+        st->optType  = TOPT_DEFAULT;
+        return SUCCESS;
+    }
+
+    if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+        fprintf(stderr, zIllOptStr, opts->pzProgPath, name);
+        (*opts->pUsageProc)(opts, EXIT_FAILURE);
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE); /* to be certain */
+    }
+
+    return FAILURE;
+}
+
+/**
+ *  Several options match the provided name.
+ *
+ * @param opts      option data
+ * @param name      name of option to look for
+ * @param match_ct  number of matching options
+ *
+ * @return success status (always FAILURE, if it returns)
+ */
+static tSuccess
+opt_ambiguous(tOptions * opts, char const * name, int match_ct)
+{
+    if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+        fprintf(stderr, zAmbigOptStr, opts->pzProgPath, name, match_ct);
+        if (match_ct <= 4)
+            opt_ambiguities(opts, name, strlen(name));
+        (*opts->pUsageProc)(opts, EXIT_FAILURE);
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE); /* to be certain */
+    }
+    return FAILURE;
+}
+
+/*=export_func  optionVendorOption
+ * private:
+ *
+ * what:  Process a vendor option
+ * arg:   + tOptions * + pOpts    + program options descriptor +
+ * arg:   + tOptDesc * + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  For POSIX specified utilities, the options are constrained to the options,
+ *  @xref{config attributes, Program Configuration}.  AutoOpts clients should
+ *  never specify this directly.  It gets referenced when the option
+ *  definitions contain a "vendor-opt" attribute.
+=*/
+void
+optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
+{
+    tOptState     opt_st   = OPTSTATE_INITIALIZER(PRESET);
+    unsigned long st_flags = opt_st.flags;
+    tSuccess      res;
+    char const *  vopt_str = pOD->optArg.argString;
+
+    if ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
+        goto illegal;
+
+    if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
+        st_flags = OPTST_DEFINED;
+    res = opt_find_long(pOpts, vopt_str, &opt_st);
+
+    switch (res) {
+    case FAILURE:
+    case PROBLEM:
+    illegal:
+        fprintf(stderr, zIllVendOptStr, vopt_str);
+        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+
+    case SUCCESS:
+        if (! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)))
+            goto illegal;
+
+        /*
+         *  See if we are in immediate handling state.
+         */
+        if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
+            /*
+             *  See if the enclosed option is okay with that state.
+             */
+            if (DO_IMMEDIATELY(opt_st.flags))
+                (void)handle_opt(pOpts, &opt_st);
+
+        } else {
+            /*
+             *  non-immediate direction.
+             *  See if the enclosed option is okay with that state.
+             */
+            if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
+                (void)handle_opt(pOpts, &opt_st);
+        }
+    }
+}
+
+/**
+ *  Find the option descriptor by full name.
+ *
+ * @param pOpts      option data
+ * @param opt_name   name of option to look for
+ * @param pOptState  state about current option
+ *
+ * @return success status
+ */
+LOCAL tSuccess
+opt_find_long(tOptions * pOpts, char const * opt_name, tOptState * pOptState)
+{
+    char    name_buf[128];
+    char *  opt_arg;
+    int     nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf));
+
+    int     matchIdx = 0;
+    ag_bool disable  = AG_FALSE;
+    int     match_ct =
+        opt_match_ct(pOpts, opt_name, nm_len, &matchIdx, &disable);
+
+    /*
+     *  See if we found one match, no matches or multiple matches.
+     */
+    switch (match_ct) {
+    case 1:  return opt_set(pOpts, opt_arg, matchIdx, disable, pOptState);
+    case 0:  return opt_unknown(pOpts, opt_name, opt_arg, pOptState);
+    default: return opt_ambiguous(pOpts, opt_name, match_ct);
+    }
+}
+
+
+/**
+ *  Find the short option descriptor for the current option
+ *
+ * @param pOpts      option data
+ * @param optValue   option flag character
+ * @param pOptState  state about current option
+ */
+LOCAL tSuccess
+opt_find_short(tOptions* pOpts, uint_t optValue, tOptState* pOptState)
+{
+    tOptDesc*  pRes = pOpts->pOptDesc;
+    int        ct   = pOpts->optCt;
+
+    /*
+     *  Search the option list
+     */
+    do  {
+        if (optValue != pRes->optValue)
+            continue;
+
+        if (SKIP_OPT(pRes)) {
+            if (  (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
+               && (pRes->pz_Name != NULL)) {
+                fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name);
+                if (pRes->pzText != NULL)
+                    fprintf(stderr, " -- %s", pRes->pzText);
+                fputc('\n', stderr);
+                (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+                /* NOTREACHED */
+                _exit(EXIT_FAILURE); /* to be certain */
+            }
+            goto short_opt_error;
+        }
+
+        pOptState->pOD     = pRes;
+        pOptState->optType = TOPT_SHORT;
+        return SUCCESS;
+
+    } while (pRes++, --ct > 0);
+
+    /*
+     *  IF    the character value is a digit
+     *    AND there is a special number option ("-n")
+     *  THEN the result is the "option" itself and the
+     *       option is the specially marked "number" option.
+     */
+    if (  IS_DEC_DIGIT_CHAR(optValue)
+       && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
+        pOptState->pOD = \
+        pRes           = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
+        (pOpts->pzCurOpt)--;
+        pOptState->optType = TOPT_SHORT;
+        return SUCCESS;
+    }
+
+short_opt_error:
+
+    /*
+     *  IF we are to stop on errors (the default, actually)
+     *  THEN call the usage procedure.
+     */
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
+        fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue);
+        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE); /* to be certain */
+    }
+
+    return FAILURE;
+}
+
+LOCAL tSuccess
+get_opt_arg(tOptions * pOpts, tOptState * pOptState)
+{
+    pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK);
+
+    /*
+     *  Figure out what to do about option arguments.  An argument may be
+     *  required, not associated with the option, or be optional.  We detect the
+     *  latter by examining for an option marker on the next possible argument.
+     *  Disabled mode option selection also disables option arguments.
+     */
+    {
+        enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE;
+        tSuccess res;
+
+        if ((pOptState->flags & OPTST_DISABLED) != 0)
+            arg_type = ARG_NONE;
+
+        else if (OPTST_GET_ARGTYPE(pOptState->flags) == OPARG_TYPE_NONE)
+            arg_type = ARG_NONE;
+
+        else if (pOptState->flags & OPTST_ARG_OPTIONAL)
+            arg_type = ARG_MAY;
+
+        else
+            arg_type = ARG_MUST;
+
+        switch (arg_type) {
+        case ARG_MUST: res = next_opt_arg_must(pOpts, pOptState); break;
+        case ARG_MAY:  res = next_opt_arg_may( pOpts, pOptState); break;
+        case ARG_NONE: res = next_opt_arg_none(pOpts, pOptState); break;
+        }
+
+        return res;
+    }
+}
+
+/**
+ *  Find the option descriptor for the current option
+ */
+LOCAL tSuccess
+find_opt(tOptions * pOpts, tOptState * pOptState)
+{
+    /*
+     *  IF we are continuing a short option list (e.g. -xyz...)
+     *  THEN continue a single flag option.
+     *  OTHERWISE see if there is room to advance and then do so.
+     */
+    if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL))
+        return opt_find_short(pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState);
+
+    if (pOpts->curOptIdx >= pOpts->origArgCt)
+        return PROBLEM; /* NORMAL COMPLETION */
+
+    pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ];
+
+    /*
+     *  IF all arguments must be named options, ...
+     */
+    if (NAMED_OPTS(pOpts)) {
+        char *   pz  = pOpts->pzCurOpt;
+        int      def;
+        tSuccess res; 
+        tAoUS *  def_opt;
+
+        pOpts->curOptIdx++;
+
+        if (*pz != '-')
+            return opt_find_long(pOpts, pz, pOptState);
+
+        /*
+         *  The name is prefixed with one or more hyphens.  Strip them off
+         *  and disable the "default_opt" setting.  Use heavy recasting to
+         *  strip off the "const" quality of the "default_opt" field.
+         */
+        while (*(++pz) == '-')   ;
+        def_opt = (void *)&(pOpts->specOptIdx.default_opt);
+        def = *def_opt;
+        *def_opt = NO_EQUIVALENT;
+        res = opt_find_long(pOpts, pz, pOptState);
+        *def_opt = def;
+        return res;
+    }
+
+    /*
+     *  Note the kind of flag/option marker
+     */
+    if (*((pOpts->pzCurOpt)++) != '-')
+        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
+
+    /*
+     *  Special hack for a hyphen by itself
+     */
+    if (*(pOpts->pzCurOpt) == NUL)
+        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
+
+    /*
+     *  The current argument is to be processed as an option argument
+     */
+    pOpts->curOptIdx++;
+
+    /*
+     *  We have an option marker.
+     *  Test the next character for long option indication
+     */
+    if (pOpts->pzCurOpt[0] == '-') {
+        if (*++(pOpts->pzCurOpt) == NUL)
+            /*
+             *  NORMAL COMPLETION - NOT this arg, but rest are operands
+             */
+            return PROBLEM;
+
+        /*
+         *  We do not allow the hyphen to be used as a flag value.
+         *  Therefore, if long options are not to be accepted, we punt.
+         */
+        if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) {
+            fprintf(stderr, zIllOptStr, pOpts->pzProgPath,
+                    pOpts->pzCurOpt-2);
+            return FAILURE;
+        }
+
+        return opt_find_long(pOpts, pOpts->pzCurOpt, pOptState);
+    }
+
+    /*
+     *  If short options are not allowed, then do long
+     *  option processing.  Otherwise the character must be a
+     *  short (i.e. single character) option.
+     */
+    if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0)
+        return opt_find_short(pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState);
+
+    return opt_find_long(pOpts, pOpts->pzCurOpt, pOptState);
+}
diff --git a/libopts/genshell.c b/libopts/genshell.c
new file mode 100644 (file)
index 0000000..230b13d
--- /dev/null
@@ -0,0 +1,415 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (genshell.c)
+ *  
+ *  It has been AutoGen-ed  December 29, 2011 at 12:02:33 PM by AutoGen 5.14
+ *  From the definitions    genshell.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 36:1:11 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This source file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the genshellopt author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * The genshellopt program is copyrighted and licensed
+ * under the following terms:
+ *
+ *  Copyright (C) 1999-2011 Bruce Korb, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *
+ *  genshellopt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  genshellopt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define OPTION_CODE_COMPILE 1
+#include "genshell.h"
+#ifdef  __cplusplus
+extern "C" {
+#endif
+extern FILE * option_usage_fp;
+
+/* TRANSLATORS: choose the translation for option names wisely because you
+                cannot ever change your mind. */
+#define zCopyright      (genshellopt_opt_strs+0)
+#define zLicenseDescrip (genshellopt_opt_strs+260)
+
+extern tUsageProc genshelloptUsage;
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+/*
+ *  genshellopt option static const strings
+ */
+static char const genshellopt_opt_strs[1691] =
+/*     0 */ "genshellopt 1\n"
+            "Copyright (C) 1999-2011 Bruce Korb, all rights reserved.\n"
+            "This is free software. It is licensed for use, modification and\n"
+            "redistribution under the terms of the\n"
+            "GNU General Public License, version 3 or later\n"
+            "    <http://gnu.org/licenses/gpl.html>\n\0"
+/*   260 */ "genshellopt is free software: you can redistribute it and/or modify it\n"
+            "under the terms of the GNU General Public License as published by the\n"
+            "Free Software Foundation, either version 3 of the License, or (at your\n"
+            "option) any later version.\n\n"
+            "genshellopt is distributed in the hope that it will be useful, but WITHOUT\n"
+            "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n"
+            "FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n"
+            "for more details.\n\n"
+            "You should have received a copy of the GNU General Public License along\n"
+            "with this program.  If not, see <http://www.gnu.org/licenses/>.\n\0"
+/*   871 */ "Output Script File\0"
+/*   890 */ "SCRIPT\0"
+/*   897 */ "script\0"
+/*   904 */ "Shell name (follows \"#!\" magic)\0"
+/*   936 */ "SHELL\0"
+/*   942 */ "no-shell\0"
+/*   951 */ "no\0"
+/*   954 */ "Display extended usage information and exit\0"
+/*   998 */ "help\0"
+/*  1003 */ "Extended usage information passed thru pager\0"
+/*  1048 */ "more-help\0"
+/*  1058 */ "Output version information and exit\0"
+/*  1094 */ "version\0"
+/*  1102 */ "GENSHELLOPT\0"
+/*  1114 */ "genshellopt - Generate Shell Option Processing Script - Ver. 1\n"
+            "USAGE:  %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0"
+/*  1235 */ "autogen-users@lists.sourceforge.net\0"
+/*  1271 */ "\n"
+            "Note that ``shell'' is only useful if the output file does not already\n"
+            "exist.  If it does, then the shell name and optional first argument will\n"
+            "be extracted from the script file.\n\0"
+/*  1452 */ "\n"
+            "If the script file already exists and contains Automated Option Processing\n"
+            "text, the second line of the file through the ending tag will be replaced\n"
+            "by the newly generated text.  The first ``#!''  line will be regenerated.\n\0"
+/*  1677 */ "genshellopt 1";
+
+/*
+ *  script option description:
+ */
+#define SCRIPT_DESC      (genshellopt_opt_strs+871)
+#define SCRIPT_NAME      (genshellopt_opt_strs+890)
+#define SCRIPT_name      (genshellopt_opt_strs+897)
+#define SCRIPT_FLAGS     (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  shell option description:
+ */
+#define SHELL_DESC      (genshellopt_opt_strs+904)
+#define SHELL_NAME      (genshellopt_opt_strs+936)
+#define NOT_SHELL_name  (genshellopt_opt_strs+942)
+#define NOT_SHELL_PFX   (genshellopt_opt_strs+951)
+#define SHELL_name      (NOT_SHELL_name + 3)
+#define SHELL_FLAGS     (OPTST_INITENABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Help/More_Help/Version option descriptions:
+ */
+#define HELP_DESC       (genshellopt_opt_strs+954)
+#define HELP_name       (genshellopt_opt_strs+998)
+#ifdef HAVE_WORKING_FORK
+#define MORE_HELP_DESC  (genshellopt_opt_strs+1003)
+#define MORE_HELP_name  (genshellopt_opt_strs+1048)
+#define MORE_HELP_FLAGS (OPTST_IMM | OPTST_NO_INIT)
+#else
+#define MORE_HELP_DESC  NULL
+#define MORE_HELP_name  NULL
+#define MORE_HELP_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
+#endif
+#ifdef NO_OPTIONAL_OPT_ARGS
+#  define VER_FLAGS     (OPTST_IMM | OPTST_NO_INIT)
+#else
+#  define VER_FLAGS     (OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
+                         OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT)
+#endif
+#define VER_DESC        (genshellopt_opt_strs+1058)
+#define VER_name        (genshellopt_opt_strs+1094)
+/*
+ *  Declare option callback procedures
+ */
+extern tOptProc
+    optionBooleanVal,   optionNestedVal,    optionNumericVal,
+    optionPagedUsage,   optionPrintVersion, optionResetOpt,
+    optionStackArg,     optionTimeDate,     optionTimeVal,
+    optionUnstackArg,   optionVendorOption;
+static tOptProc
+    doUsageOpt;
+#define VER_PROC        optionPrintVersion
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Genshellopt Option Descriptions.
+ */
+static tOptDesc optDesc[GENSHELL_OPTION_CT] = {
+  {  /* entry idx, value */ 0, VALUE_GENSHELL_OPT_SCRIPT,
+     /* equiv idx, value */ 0, VALUE_GENSHELL_OPT_SCRIPT,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ SCRIPT_FLAGS, 0,
+     /* last opt argumnt */ { NULL }, /* --script */
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ SCRIPT_DESC, SCRIPT_NAME, SCRIPT_name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 1, VALUE_GENSHELL_OPT_SHELL,
+     /* equiv idx, value */ 1, VALUE_GENSHELL_OPT_SHELL,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ SHELL_FLAGS, 0,
+     /* last opt argumnt */ { NULL }, /* --shell */
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ SHELL_DESC, SHELL_NAME, SHELL_name,
+     /* disablement strs */ NOT_SHELL_name, NOT_SHELL_PFX },
+
+  {  /* entry idx, value */ INDEX_GENSHELL_OPT_VERSION, VALUE_GENSHELL_OPT_VERSION,
+     /* equiv idx value  */ NO_EQUIVALENT, VALUE_GENSHELL_OPT_VERSION,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ VER_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ VER_PROC,
+     /* desc, NAME, name */ VER_DESC, NULL, VER_name,
+     /* disablement strs */ NULL, NULL },
+
+
+
+  {  /* entry idx, value */ INDEX_GENSHELL_OPT_HELP, VALUE_GENSHELL_OPT_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, VALUE_GENSHELL_OPT_HELP,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_IMM | OPTST_NO_INIT, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doUsageOpt,
+     /* desc, NAME, name */ HELP_DESC, NULL, HELP_name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ INDEX_GENSHELL_OPT_MORE_HELP, VALUE_GENSHELL_OPT_MORE_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, VALUE_GENSHELL_OPT_MORE_HELP,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ MORE_HELP_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL,  NULL,
+     /* option proc      */ optionPagedUsage,
+     /* desc, NAME, name */ MORE_HELP_DESC, NULL, MORE_HELP_name,
+     /* disablement strs */ NULL, NULL }
+};
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Genshellopt Option Environment
+ */
+#define zPROGNAME       (genshellopt_opt_strs+1102)
+#define zUsageTitle     (genshellopt_opt_strs+1114)
+#define zRcName         NULL
+#define apzHomeList     NULL
+#define zBugsAddr       (genshellopt_opt_strs+1235)
+#define zExplain        (genshellopt_opt_strs+1271)
+#define zDetail         (genshellopt_opt_strs+1452)
+#define zFullVersion    (genshellopt_opt_strs+1677)
+/* extracted from optcode.tlib near line 315 */
+
+#if defined(ENABLE_NLS)
+# define OPTPROC_BASE OPTPROC_TRANSLATE
+  static tOptionXlateProc translate_option_strings;
+#else
+# define OPTPROC_BASE OPTPROC_NONE
+# define translate_option_strings NULL
+#endif /* ENABLE_NLS */
+
+
+#define genshellopt_full_usage (NULL)
+
+#define genshellopt_short_usage (NULL)
+
+/*
+ *  Create the static procedure(s) declared above.
+ */
+static void
+doUsageOpt(tOptions * pOptions, tOptDesc * pOptDesc)
+{
+    (void)pOptions;
+    GENSHELL_USAGE(GENSHELLOPT_EXIT_SUCCESS);
+}
+/* extracted from optmain.tlib near line 1148 */
+
+#ifndef  PKGDATADIR
+# define PKGDATADIR ""
+#endif
+
+#ifndef  WITH_PACKAGER
+# define genshellopt_packager_info NULL
+#else
+static char const genshellopt_packager_info[] =
+    "Packaged by " WITH_PACKAGER
+
+# ifdef WITH_PACKAGER_VERSION
+        " ("WITH_PACKAGER_VERSION")"
+# endif
+
+# ifdef WITH_PACKAGER_BUG_REPORTS
+    "\nReport genshellopt bugs to " WITH_PACKAGER_BUG_REPORTS
+# endif
+    "\n";
+#endif
+
+tOptions genshelloptOptions = {
+    OPTIONS_STRUCT_VERSION,
+    0, NULL,                    /* original argc + argv    */
+    ( OPTPROC_BASE
+    + OPTPROC_ERRSTOP
+    + OPTPROC_SHORTOPT
+    + OPTPROC_LONGOPT
+    + OPTPROC_NO_REQ_OPT
+    + OPTPROC_NEGATIONS
+    + OPTPROC_NO_ARGS ),
+    0, NULL,                    /* current option index, current option */
+    NULL,         NULL,         zPROGNAME,
+    zRcName,      zCopyright,   zLicenseDescrip,
+    zFullVersion, apzHomeList,  zUsageTitle,
+    zExplain,     zDetail,      optDesc,
+    zBugsAddr,                  /* address to send bugs to */
+    NULL, NULL,                 /* extensions/saved state  */
+    genshelloptUsage, /* usage procedure */
+    translate_option_strings,   /* translation procedure */
+    /*
+     *  Indexes to special options
+     */
+    { INDEX_GENSHELL_OPT_MORE_HELP, /* more-help option index */
+      NO_EQUIVALENT, /* save option index */
+      NO_EQUIVALENT, /* '-#' option index */
+      NO_EQUIVALENT /* index of default opt */
+    },
+    5 /* full option count */, 2 /* user option count */,
+    genshellopt_full_usage, genshellopt_short_usage,
+    NULL, NULL,
+    PKGDATADIR, genshellopt_packager_info
+};
+
+#if ENABLE_NLS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <autoopts/usage-txt.h>
+
+static char* AO_gettext(char const* pz);
+static void  coerce_it(void** s);
+
+static char*
+AO_gettext(char const* pz)
+{
+    char* pzRes;
+    if (pz == NULL)
+        return NULL;
+    pzRes = _(pz);
+    if (pzRes == pz)
+        return pzRes;
+    pzRes = strdup(pzRes);
+    if (pzRes == NULL) {
+        fputs(_("No memory for duping translated strings\n"), stderr);
+        exit(GENSHELLOPT_EXIT_FAILURE);
+    }
+    return pzRes;
+}
+
+static void coerce_it(void** s) { *s = AO_gettext(*s);
+}
+
+/*
+ *  This invokes the translation code (e.g. gettext(3)).
+ */
+static void
+translate_option_strings(void)
+{
+    tOptions * const pOpt = &genshelloptOptions;
+
+    /*
+     *  Guard against re-translation.  It won't work.  The strings will have
+     *  been changed by the first pass through this code.  One shot only.
+     */
+    if (option_usage_text.field_ct != 0) {
+        /*
+         *  Do the translations.  The first pointer follows the field count
+         *  field.  The field count field is the size of a pointer.
+         */
+        tOptDesc * pOD = pOpt->pOptDesc;
+        char **    ppz = (char**)(void*)&(option_usage_text);
+        int        ix  = option_usage_text.field_ct;
+
+        do {
+            ppz++;
+            *ppz = AO_gettext(*ppz);
+        } while (--ix > 0);
+
+        coerce_it((void*)&(pOpt->pzCopyright));
+        coerce_it((void*)&(pOpt->pzCopyNotice));
+        coerce_it((void*)&(pOpt->pzFullVersion));
+        coerce_it((void*)&(pOpt->pzUsageTitle));
+        coerce_it((void*)&(pOpt->pzExplain));
+        coerce_it((void*)&(pOpt->pzDetail));
+        coerce_it((void*)&(pOpt->pzPackager));
+        option_usage_text.field_ct = 0;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++)
+            coerce_it((void*)&(pOD->pzText));
+    }
+
+    if ((pOpt->fOptSet & OPTPROC_NXLAT_OPT_CFG) == 0) {
+        tOptDesc * pOD = pOpt->pOptDesc;
+        int        ix;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++) {
+            coerce_it((void*)&(pOD->pz_Name));
+            coerce_it((void*)&(pOD->pz_DisableName));
+            coerce_it((void*)&(pOD->pz_DisablePfx));
+        }
+        /* prevent re-translation */
+        genshelloptOptions.fOptSet |= OPTPROC_NXLAT_OPT_CFG | OPTPROC_NXLAT_OPT;
+    }
+}
+
+#endif /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+/* genshell.c ends here */
diff --git a/libopts/genshell.h b/libopts/genshell.h
new file mode 100644 (file)
index 0000000..2718bbf
--- /dev/null
@@ -0,0 +1,177 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (genshell.h)
+ *  
+ *  It has been AutoGen-ed  December 29, 2011 at 12:02:33 PM by AutoGen 5.14
+ *  From the definitions    genshell.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 36:1:11 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This header file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the genshellopt author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * The genshellopt program is copyrighted and licensed
+ * under the following terms:
+ *
+ *  Copyright (C) 1999-2011 Bruce Korb, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *
+ *  genshellopt is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  genshellopt is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ *  This file contains the programmatic interface to the Automated
+ *  Options generated for the genshellopt program.
+ *  These macros are documented in the AutoGen info file in the
+ *  "AutoOpts" chapter.  Please refer to that doc for usage help.
+ */
+#ifndef AUTOOPTS_GENSHELL_H_GUARD
+#define AUTOOPTS_GENSHELL_H_GUARD 1
+#include <autoopts/options.h>
+
+/*
+ *  Ensure that the library used for compiling this generated header is at
+ *  least as new as the version current when the header template was released
+ *  (not counting patch version increments).  Also ensure that the oldest
+ *  tolerable version is at least as old as what was current when the header
+ *  template was released.
+ */
+#define AO_TEMPLATE_VERSION 147457
+#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
+ || (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
+# error option template version mismatches autoopts/options.h header
+  Choke Me.
+#endif
+
+/*
+ *  Enumeration of each option:
+ */
+typedef enum {
+    INDEX_GENSHELL_OPT_SCRIPT      =  0,
+    INDEX_GENSHELL_OPT_SHELL       =  1,
+    INDEX_GENSHELL_OPT_VERSION     =  2,
+    INDEX_GENSHELL_OPT_HELP        =  3,
+    INDEX_GENSHELL_OPT_MORE_HELP   =  4
+} teGenshell_OptIndex;
+
+#define GENSHELL_OPTION_CT    5
+#define GENSHELLOPT_VERSION       "1"
+#define GENSHELLOPT_FULL_VERSION  "genshellopt 1"
+
+/*
+ *  Interface defines for all options.  Replace "n" with the UPPER_CASED
+ *  option name (as in the teGenshell_OptIndex enumeration above).
+ *  e.g. HAVE_GENSHELL_OPT(SCRIPT)
+ */
+#define GENSHELL_DESC(n) (genshelloptOptions.pOptDesc[INDEX_GENSHELL_OPT_## n])
+#define     HAVE_GENSHELL_OPT(n) (! UNUSED_OPT(& GENSHELL_DESC(n)))
+#define      GENSHELL_OPT_ARG(n) (GENSHELL_DESC(n).optArg.argString)
+#define    STATE_GENSHELL_OPT(n) (GENSHELL_DESC(n).fOptState & OPTST_SET_MASK)
+#define    COUNT_GENSHELL_OPT(n) (GENSHELL_DESC(n).optOccCt)
+#define    ISSEL_GENSHELL_OPT(n) (SELECTED_OPT(&GENSHELL_DESC(n)))
+#define ISUNUSED_GENSHELL_OPT(n) (UNUSED_OPT(& GENSHELL_DESC(n)))
+#define  ENABLED_GENSHELL_OPT(n) (! DISABLED_OPT(& GENSHELL_DESC(n)))
+#define  STACKCT_GENSHELL_OPT(n) (((tArgList*)(GENSHELL_DESC(n).optCookie))->useCt)
+#define STACKLST_GENSHELL_OPT(n) (((tArgList*)(GENSHELL_DESC(n).optCookie))->apzArgs)
+#define    CLEAR_GENSHELL_OPT(n) STMTS( \
+                GENSHELL_DESC(n).fOptState &= OPTST_PERSISTENT_MASK;   \
+                if ((GENSHELL_DESC(n).fOptState & OPTST_INITENABLED) == 0) \
+                    GENSHELL_DESC(n).fOptState |= OPTST_DISABLED; \
+                GENSHELL_DESC(n).optCookie = NULL )
+
+/* * * * * *
+ *
+ *  Enumeration of genshellopt exit codes
+ */
+typedef enum {
+    GENSHELLOPT_EXIT_SUCCESS = 0,
+    GENSHELLOPT_EXIT_FAILURE = 1
+} genshellopt_exit_code_t;
+/* * * * * *
+ *
+ *  Interface defines for specific options.
+ */
+#define VALUE_GENSHELL_OPT_SCRIPT 'o'
+#define VALUE_GENSHELL_OPT_SHELL 's'
+#define VALUE_GENSHELL_OPT_HELP '?'
+#define VALUE_GENSHELL_OPT_MORE_HELP '!'
+#define VALUE_GENSHELL_OPT_VERSION 'v'
+/*
+ *  Interface defines not associated with particular options
+ */
+#define ERRSKIP_GENSHELL_OPTERR  STMTS(genshelloptOptions.fOptSet &= ~OPTPROC_ERRSTOP)
+#define ERRSTOP_GENSHELL_OPTERR  STMTS(genshelloptOptions.fOptSet |= OPTPROC_ERRSTOP)
+#define RESTART_GENSHELL_OPT(n)  STMTS( \
+                genshelloptOptions.curOptIdx = (n); \
+                genshelloptOptions.pzCurOpt  = NULL )
+#define START_GENSHELL_OPT       RESTART_GENSHELL_OPT(1)
+#define GENSHELL_USAGE(c)        (*genshelloptOptions.pUsageProc)(&genshelloptOptions, c)
+/* extracted from opthead.tlib near line 469 */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* * * * * *
+ *
+ *  Declare the genshellopt option descriptor.
+ */
+extern tOptions genshelloptOptions;
+
+#if defined(ENABLE_NLS)
+# ifndef _
+#   include <stdio.h>
+static inline char* aoGetsText(char const* pz) {
+    if (pz == NULL) return NULL;
+    return (char*)gettext(pz);
+}
+#   define _(s)  aoGetsText(s)
+# endif /* _() */
+
+# define OPT_NO_XLAT_CFG_NAMES  STMTS(genshelloptOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT_CFG;)
+# define OPT_NO_XLAT_OPT_NAMES  STMTS(genshelloptOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG;)
+
+# define OPT_XLAT_CFG_NAMES     STMTS(genshelloptOptions.fOptSet &= \
+                                  ~(OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG);)
+# define OPT_XLAT_OPT_NAMES     STMTS(genshelloptOptions.fOptSet &= \
+                                  ~OPTPROC_NXLAT_OPT;)
+
+#else   /* ENABLE_NLS */
+# define OPT_NO_XLAT_CFG_NAMES
+# define OPT_NO_XLAT_OPT_NAMES
+
+# define OPT_XLAT_CFG_NAMES
+# define OPT_XLAT_OPT_NAMES
+
+# ifndef _
+#   define _(_s)  _s
+# endif
+#endif  /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif /* AUTOOPTS_GENSHELL_H_GUARD */
+/* genshell.h ends here */
diff --git a/libopts/libopts.c b/libopts/libopts.c
new file mode 100644 (file)
index 0000000..ca256eb
--- /dev/null
@@ -0,0 +1,43 @@
+#include "autoopts/project.h"
+#define  AUTOOPTS_INTERNAL 1
+#include "compat/compat.h"
+#define  LOCAL static
+#include "autoopts/options.h"
+#include "autoopts/usage-txt.h"
+#include "genshell.h"
+#include "xat-attribute.h"
+#include "value-type.h"
+#include "ag-char-map.h"
+#include "autoopts.h"
+#include "proto.h"
+#include "parse-duration.h"
+#include "parse-duration.c"
+#include "value-type.c"
+#include "xat-attribute.c"
+#include "autoopts.c"
+#include "boolean.c"
+#include "configfile.c"
+#include "cook.c"
+#include "check.c"
+#include "enum.c"
+#include "env.c"
+#include "file.c"
+#include "find.c"
+#include "genshell.c"
+#include "load.c"
+#include "makeshell.c"
+#include "nested.c"
+#include "numeric.c"
+#include "pgusage.c"
+#include "putshell.c"
+#include "reset.c"
+#include "restore.c"
+#include "save.c"
+#include "sort.c"
+#include "stack.c"
+#include "streqvcmp.c"
+#include "text_mmap.c"
+#include "tokenize.c"
+#include "time.c"
+#include "usage.c"
+#include "version.c"
diff --git a/libopts/load.c b/libopts/load.c
new file mode 100644 (file)
index 0000000..e4f231d
--- /dev/null
@@ -0,0 +1,517 @@
+
+/**
+ *  \file load.c
+ *  Time-stamp:      "2011-12-17 12:53:04 bkorb"
+ *
+ *  This file contains the routines that deal with processing text strings
+ *  for options, either from a NUL-terminated string passed in or from an
+ *  rc/ini file.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static ag_bool
+add_prog_path(char * pzBuf, int bufSize, char const * pzName,
+              char const * pzProgPath);
+
+static ag_bool
+add_env_val(char * pzBuf, int bufSize, char const * pzName,
+            char const * pzProgPath);
+
+static char*
+assemble_arg_val(char* pzTxt, tOptionLoadMode mode);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*=export_func  optionMakePath
+ * private:
+ *
+ * what:  translate and construct a path
+ * arg:   + char*       + pzBuf      + The result buffer +
+ * arg:   + int         + bufSize    + The size of this buffer +
+ * arg:   + char const* + pzName     + The input name +
+ * arg:   + char const* + pzProgPath + The full path of the current program +
+ *
+ * ret-type: ag_bool
+ * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE.
+ *           If the name does not start with ``$'', then it is handled
+ *           simply by copying the input name to the output buffer and
+ *           resolving the name with either
+ *           @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}.
+ *
+ * doc:
+ *
+ *  This routine will copy the @code{pzName} input name into the
+ *  @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes.  If the
+ *  first character of the input name is a @code{'$'} character, then there
+ *  is special handling:
+ *  @*
+ *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
+ *  searching @code{$PATH} if necessary.
+ *  @*
+ *  @code{$@} is replaced with the AutoGen package data installation directory
+ *  (aka @code{pkgdatadir}).
+ *  @*
+ *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
+ *  variable.  If not found, the search fails.
+ *
+ *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
+ *     @code{pzName} string and must either be the entire string or be followed
+ *     by the @code{'/'} (backslash on windows) character.
+ *
+ * err:  @code{AG_FALSE} is returned if:
+ *       @*
+ *       @bullet{} The input name exceeds @code{bufSize} bytes.
+ *       @*
+ *       @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
+ *                 and the next character is not '/'.
+ *       @*
+ *       @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
+ *                 was specified.
+ *       @*
+ *       @bullet{} @code{NAME} is not a known environment variable
+ *       @*
+ *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
+ *                 errors (cannot resolve the resulting path).
+=*/
+ag_bool
+optionMakePath(char * pzBuf, int bufSize, char const * pzName,
+               char const * pzProgPath)
+{
+    size_t name_len = strlen(pzName);
+
+    if ((bufSize <= name_len) || (name_len == 0))
+        return AG_FALSE;
+
+    /*
+     *  IF not an environment variable, just copy the data
+     */
+    if (*pzName != '$') {
+        char const*  pzS = pzName;
+        char* pzD = pzBuf;
+        int   ct  = bufSize;
+
+        for (;;) {
+            if ( (*(pzD++) = *(pzS++)) == NUL)
+                break;
+            if (--ct <= 0)
+                return AG_FALSE;
+        }
+    }
+
+    /*
+     *  IF the name starts with "$$", then it must be "$$" or
+     *  it must start with "$$/".  In either event, replace the "$$"
+     *  with the path to the executable and append a "/" character.
+     */
+    else switch (pzName[1]) {
+    case NUL:
+        return AG_FALSE;
+
+    case '$':
+        if (! add_prog_path(pzBuf, bufSize, pzName, pzProgPath))
+            return AG_FALSE;
+        break;
+
+    case '@':
+        if (program_pkgdatadir[0] == NUL)
+            return AG_FALSE;
+
+        if (snprintf(pzBuf, bufSize, "%s%s", program_pkgdatadir, pzName + 2)
+            >= bufSize)
+            return AG_FALSE;
+        break;
+
+    default:
+        if (! add_env_val(pzBuf, bufSize, pzName, pzProgPath))
+            return AG_FALSE;
+    }
+
+#if defined(HAVE_CANONICALIZE_FILE_NAME)
+    {
+        char * pz = canonicalize_file_name(pzBuf);
+        if (pz == NULL)
+            return AG_FALSE;
+
+        name_len = strlen(pz);
+        if (name_len >= bufSize) {
+            free(pz);
+            return AG_FALSE;
+        }
+
+        memcpy(pzBuf, pz, name_len + 1);
+        free(pz);
+    }
+
+#elif defined(HAVE_REALPATH)
+    {
+        char z[PATH_MAX+1];
+
+        if (realpath(pzBuf, z) == NULL)
+            return AG_FALSE;
+
+        name_len = strlen(z);
+        if (name_len >= bufSize)
+            return AG_FALSE;
+
+        memcpy(pzBuf, z, name_len + 1);
+    }
+#endif
+
+    return AG_TRUE;
+}
+
+static ag_bool
+add_prog_path(char * pzBuf, int bufSize, char const * pzName,
+              char const * pzProgPath)
+{
+    char const*    pzPath;
+    char const*    pz;
+    int     skip = 2;
+
+    switch (pzName[2]) {
+    case DIRCH:
+        skip = 3;
+    case NUL:
+        break;
+    default:
+        return AG_FALSE;
+    }
+
+    /*
+     *  See if the path is included in the program name.
+     *  If it is, we're done.  Otherwise, we have to hunt
+     *  for the program using "pathfind".
+     */
+    if (strchr(pzProgPath, DIRCH) != NULL)
+        pzPath = pzProgPath;
+    else {
+        pzPath = pathfind(getenv("PATH"), (char*)pzProgPath, "rx");
+
+        if (pzPath == NULL)
+            return AG_FALSE;
+    }
+
+    pz = strrchr(pzPath, DIRCH);
+
+    /*
+     *  IF we cannot find a directory name separator,
+     *  THEN we do not have a path name to our executable file.
+     */
+    if (pz == NULL)
+        return AG_FALSE;
+
+    pzName += skip;
+
+    /*
+     *  Concatenate the file name to the end of the executable path.
+     *  The result may be either a file or a directory.
+     */
+    if ((pz - pzPath)+1 + strlen(pzName) >= bufSize)
+        return AG_FALSE;
+
+    memcpy(pzBuf, pzPath, (size_t)((pz - pzPath)+1));
+    strcpy(pzBuf + (pz - pzPath) + 1, pzName);
+
+    /*
+     *  If the "pzPath" path was gotten from "pathfind()", then it was
+     *  allocated and we need to deallocate it.
+     */
+    if (pzPath != pzProgPath)
+        AGFREE(pzPath);
+    return AG_TRUE;
+}
+
+
+static ag_bool
+add_env_val(char * pzBuf, int bufSize, char const * pzName,
+            char const * pzProgPath)
+{
+    char* pzDir = pzBuf;
+
+    for (;;) {
+        int ch = (int)*++pzName;
+        if (! IS_VALUE_NAME_CHAR(ch))
+            break;
+        *(pzDir++) = (char)ch;
+    }
+
+    if (pzDir == pzBuf)
+        return AG_FALSE;
+
+    *pzDir = NUL;
+
+    pzDir = getenv(pzBuf);
+
+    /*
+     *  Environment value not found -- skip the home list entry
+     */
+    if (pzDir == NULL)
+        return AG_FALSE;
+
+    if (strlen(pzDir) + 1 + strlen(pzName) >= bufSize)
+        return AG_FALSE;
+
+    sprintf(pzBuf, "%s%s", pzDir, pzName);
+    return AG_TRUE;
+}
+
+
+LOCAL void
+mungeString(char* pzTxt, tOptionLoadMode mode)
+{
+    char* pzE;
+
+    if (mode == OPTION_LOAD_KEEP)
+        return;
+
+    if (IS_WHITESPACE_CHAR(*pzTxt)) {
+        char* pzS = pzTxt;
+        char* pzD = pzTxt;
+        while (IS_WHITESPACE_CHAR(*++pzS))  ;
+        while ((*(pzD++) = *(pzS++)) != NUL)   ;
+        pzE = pzD-1;
+    } else
+        pzE = pzTxt + strlen(pzTxt);
+
+    while ((pzE > pzTxt) && IS_WHITESPACE_CHAR(pzE[-1]))  pzE--;
+    *pzE = NUL;
+
+    if (mode == OPTION_LOAD_UNCOOKED)
+        return;
+
+    switch (*pzTxt) {
+    default: return;
+    case '"':
+    case '\'': break;
+    }
+
+    switch (pzE[-1]) {
+    default: return;
+    case '"':
+    case '\'': break;
+    }
+
+    (void)ao_string_cook(pzTxt, NULL);
+}
+
+
+static char*
+assemble_arg_val(char* pzTxt, tOptionLoadMode mode)
+{
+    static char const zBrk[] = " \t\n:=";
+    char* pzEnd = strpbrk(pzTxt, zBrk);
+    int   space_break;
+
+    /*
+     *  Not having an argument to a configurable name is okay.
+     */
+    if (pzEnd == NULL)
+        return pzTxt + strlen(pzTxt);
+
+    /*
+     *  If we are keeping all whitespace, then the  modevalue starts with the
+     *  character that follows the end of the configurable name, regardless
+     *  of which character caused it.
+     */
+    if (mode == OPTION_LOAD_KEEP) {
+        *(pzEnd++) = NUL;
+        return pzEnd;
+    }
+
+    /*
+     *  If the name ended on a white space character, remember that
+     *  because we'll have to skip over an immediately following ':' or '='
+     *  (and the white space following *that*).
+     */
+    space_break = IS_WHITESPACE_CHAR(*pzEnd);
+    *(pzEnd++) = NUL;
+    while (IS_WHITESPACE_CHAR(*pzEnd))  pzEnd++;
+    if (space_break && ((*pzEnd == ':') || (*pzEnd == '=')))
+        while (IS_WHITESPACE_CHAR(*++pzEnd))  ;
+
+    return pzEnd;
+}
+
+
+/*
+ *  Load an option from a block of text.  The text must start with the
+ *  configurable/option name and be followed by its associated value.
+ *  That value may be processed in any of several ways.  See "tOptionLoadMode"
+ *  in autoopts.h.
+ */
+LOCAL void
+loadOptionLine(
+    tOptions*   pOpts,
+    tOptState*  pOS,
+    char*       pzLine,
+    tDirection  direction,
+    tOptionLoadMode   load_mode )
+{
+    while (IS_WHITESPACE_CHAR(*pzLine))  pzLine++;
+
+    {
+        char* pzArg = assemble_arg_val(pzLine, load_mode);
+
+        if (! SUCCESSFUL(opt_find_long(pOpts, pzLine, pOS)))
+            return;
+        if (pOS->flags & OPTST_NO_INIT)
+            return;
+        pOS->pzOptArg = pzArg;
+    }
+
+    switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
+    case 0:
+        /*
+         *  The selected option has no immediate action.
+         *  THEREFORE, if the direction is PRESETTING
+         *  THEN we skip this option.
+         */
+        if (PRESETTING(direction))
+            return;
+        break;
+
+    case OPTST_IMM:
+        if (PRESETTING(direction)) {
+            /*
+             *  We are in the presetting direction with an option we handle
+             *  immediately for enablement, but normally for disablement.
+             *  Therefore, skip if disabled.
+             */
+            if ((pOS->flags & OPTST_DISABLED) == 0)
+                return;
+        } else {
+            /*
+             *  We are in the processing direction with an option we handle
+             *  immediately for enablement, but normally for disablement.
+             *  Therefore, skip if NOT disabled.
+             */
+            if ((pOS->flags & OPTST_DISABLED) != 0)
+                return;
+        }
+        break;
+
+    case OPTST_DISABLE_IMM:
+        if (PRESETTING(direction)) {
+            /*
+             *  We are in the presetting direction with an option we handle
+             *  immediately for disablement, but normally for disablement.
+             *  Therefore, skip if NOT disabled.
+             */
+            if ((pOS->flags & OPTST_DISABLED) != 0)
+                return;
+        } else {
+            /*
+             *  We are in the processing direction with an option we handle
+             *  immediately for disablement, but normally for disablement.
+             *  Therefore, skip if disabled.
+             */
+            if ((pOS->flags & OPTST_DISABLED) == 0)
+                return;
+        }
+        break;
+
+    case OPTST_IMM|OPTST_DISABLE_IMM:
+        /*
+         *  The selected option is always for immediate action.
+         *  THEREFORE, if the direction is PROCESSING
+         *  THEN we skip this option.
+         */
+        if (PROCESSING(direction))
+            return;
+        break;
+    }
+
+    /*
+     *  Fix up the args.
+     */
+    if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
+        if (*pOS->pzOptArg != NUL)
+            return;
+        pOS->pzOptArg = NULL;
+
+    } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
+        if (*pOS->pzOptArg == NUL)
+             pOS->pzOptArg = NULL;
+        else {
+            AGDUPSTR(pOS->pzOptArg, pOS->pzOptArg, "option argument");
+            pOS->flags |= OPTST_ALLOC_ARG;
+        }
+
+    } else {
+        if (*pOS->pzOptArg == NUL)
+             pOS->pzOptArg = zNil;
+        else {
+            AGDUPSTR(pOS->pzOptArg, pOS->pzOptArg, "option argument");
+            pOS->flags |= OPTST_ALLOC_ARG;
+        }
+    }
+
+    {
+        tOptionLoadMode sv = option_load_mode;
+        option_load_mode = load_mode;
+        handle_opt(pOpts, pOS);
+        option_load_mode = sv;
+    }
+}
+
+
+/*=export_func  optionLoadLine
+ *
+ * what:  process a string for an option name and value
+ *
+ * arg:   tOptions*,   pOpts,  program options descriptor
+ * arg:   char const*, pzLine, NUL-terminated text
+ *
+ * doc:
+ *
+ *  This is a client program callable routine for setting options from, for
+ *  example, the contents of a file that they read in.  Only one option may
+ *  appear in the text.  It will be treated as a normal (non-preset) option.
+ *
+ *  When passed a pointer to the option struct and a string, it will find
+ *  the option named by the first token on the string and set the option
+ *  argument to the remainder of the string.  The caller must NUL terminate
+ *  the string.  Any embedded new lines will be included in the option
+ *  argument.  If the input looks like one or more quoted strings, then the
+ *  input will be "cooked".  The "cooking" is identical to the string
+ *  formation used in AutoGen definition files (@pxref{basic expression}),
+ *  except that you may not use backquotes.
+ *
+ * err:   Invalid options are silently ignored.  Invalid option arguments
+ *        will cause a warning to print, but the function should return.
+=*/
+void
+optionLoadLine(tOptions * pOpts, char const * pzLine)
+{
+    tOptState st = OPTSTATE_INITIALIZER(SET);
+    char* pz;
+    AGDUPSTR(pz, pzLine, "user option line");
+    loadOptionLine(pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED);
+    AGFREE(pz);
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/load.c */
diff --git a/libopts/makeshell.c b/libopts/makeshell.c
new file mode 100644 (file)
index 0000000..7b9b6cd
--- /dev/null
@@ -0,0 +1,1148 @@
+
+/**
+ * \file makeshell.c
+ *
+ * Time-stamp:      "2011-04-20 11:06:57 bkorb"
+ *
+ *  This module will interpret the options set in the tOptions
+ *  structure and create a Bourne shell script capable of parsing them.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+tOptions * optionParseShellOptions = NULL;
+
+/* * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Setup Format Strings
+ */
+static char const zStartMarker[] =
+"# # # # # # # # # # -- do not modify this marker --\n#\n"
+"#  DO NOT EDIT THIS SECTION";
+
+static char const zPreamble[] =
+"%s OF %s\n#\n"
+"#  From here to the next `-- do not modify this marker --',\n"
+"#  the text has been generated %s\n";
+
+static char const zEndPreamble[] =
+"#  From the %s option definitions\n#\n";
+
+static char const zMultiDef[] = "\n"
+"if test -z \"${%1$s_%2$s}\"\n"
+"then\n"
+"  %1$s_%2$s_CT=0\n"
+"else\n"
+"  %1$s_%2$s_CT=1\n"
+"  %1$s_%2$s_1=\"${%1$s_%2$s}\"\n"
+"fi\n"
+"export %1$s_%2$s_CT";
+
+static char const zSingleDef[] = "\n"
+"%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n"
+"%1$s_%2$s_set=false\n"
+"export %1$s_%2$s\n";
+
+static char const zSingleNoDef[] = "\n"
+"%1$s_%2$s=\"${%1$s_%2$s}\"\n"
+"%1$s_%2$s_set=false\n"
+"export %1$s_%2$s\n";
+
+/* * * * * * * * * * * * * * * * * * * * *
+ *
+ *  LOOP START
+ *
+ *  The loop may run in either of two modes:
+ *  all options are named options (loop only)
+ *  regular, marked option processing.
+ */
+static char const zLoopCase[] = "\n"
+"OPT_PROCESS=true\n"
+"OPT_ARG=\"$1\"\n\n"
+"while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n"
+"    OPT_ELEMENT=''\n"
+"    OPT_ARG_VAL=''\n\n"
+     /*
+      *  'OPT_ARG' may or may not match the current $1
+      */
+"    case \"${OPT_ARG}\" in\n"
+"    -- )\n"
+"        OPT_PROCESS=false\n"
+"        shift\n"
+"        ;;\n\n";
+
+static char const zLoopOnly[] = "\n"
+"OPT_ARG=\"$1\"\n\n"
+"while [ $# -gt 0 ]\ndo\n"
+"    OPT_ELEMENT=''\n"
+"    OPT_ARG_VAL=''\n\n"
+"    OPT_ARG=\"${1}\"\n";
+
+/* * * * * * * * * * * * * * * *
+ *
+ *  CASE SELECTORS
+ *
+ *  If the loop runs as a regular option loop,
+ *  then we must have selectors for each acceptable option
+ *  type (long option, flag character and non-option)
+ */
+static char const zLongSelection[] =
+"    --* )\n";
+
+static char const zFlagSelection[] =
+"    -* )\n";
+
+static char const zEndSelection[] =
+"        ;;\n\n";
+
+static char const zNoSelection[] =
+"    * )\n"
+"         OPT_PROCESS=false\n"
+"         ;;\n"
+"    esac\n\n";
+
+/* * * * * * * * * * * * * * * *
+ *
+ *  LOOP END
+ */
+static char const zLoopEnd[] =
+"    if [ -n \"${OPT_ARG_VAL}\" ]\n"
+"    then\n"
+"        eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n"
+"        export %1$s_${OPT_NAME}${OPT_ELEMENT}\n"
+"    fi\n"
+"done\n\n"
+"unset OPT_PROCESS || :\n"
+"unset OPT_ELEMENT || :\n"
+"unset OPT_ARG || :\n"
+"unset OPT_ARG_NEEDED || :\n"
+"unset OPT_NAME || :\n"
+"unset OPT_CODE || :\n"
+"unset OPT_ARG_VAL || :\n%2$s";
+
+static char const zTrailerMarker[] = "\n"
+"# # # # # # # # # #\n#\n"
+"#  END OF AUTOMATED OPTION PROCESSING\n"
+"#\n# # # # # # # # # # -- do not modify this marker --\n";
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  OPTION SELECTION
+ */
+static char const zOptionCase[] =
+"        case \"${OPT_CODE}\" in\n";
+
+static char const zOptionPartName[] =
+"        '%s' | \\\n";
+
+static char const zOptionFullName[] =
+"        '%s' )\n";
+
+static char const zOptionFlag[] =
+"        '%c' )\n";
+
+static char const zOptionEndSelect[] =
+"            ;;\n\n";
+
+static char const zOptionUnknown[] =
+"        * )\n"
+"            echo Unknown %s: \"${OPT_CODE}\" >&2\n"
+"            echo \"$%s_USAGE_TEXT\"\n"
+"            exit 1\n"
+"            ;;\n"
+"        esac\n\n";
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  OPTION PROCESSING
+ *
+ *  Formats for emitting the text for handling particular options
+ */
+static char const zTextExit[] =
+"            echo \"$%s_%s_TEXT\"\n"
+"            exit 0\n";
+
+static char const zPagedUsageExit[] =
+"            echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
+"            exit 0\n";
+
+static char const zCmdFmt[] =
+"            %s\n";
+
+static char const zCountTest[] =
+"            if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n"
+"                echo Error:  more than %3$d %2$s options >&2\n"
+"                echo \"$%1$s_USAGE_TEXT\"\n"
+"                exit 1 ; fi\n";
+
+static char const zMultiArg[] =
+"            %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n"
+"            OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n"
+"            OPT_NAME='%2$s'\n";
+
+static char const zSingleArg[] =
+"            if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
+"                echo Error:  duplicate %2$s option >&2\n"
+"                echo \"$%1$s_USAGE_TEXT\"\n"
+"                exit 1 ; fi\n"
+"            %1$s_%2$s_set=true\n"
+"            OPT_NAME='%2$s'\n";
+
+static char const zNoMultiArg[] =
+"            %1$s_%2$s_CT=0\n"
+"            OPT_ELEMENT=''\n"
+"            %1$s_%2$s='%3$s'\n"
+"            export %1$s_%2$s\n"
+"            OPT_NAME='%2$s'\n";
+
+static char const zNoSingleArg[] =
+"            if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
+"                echo Error:  duplicate %2$s option >&2\n"
+"                echo \"$%1$s_USAGE_TEXT\"\n"
+"                exit 1 ; fi\n"
+"            %1$s_%2$s_set=true\n"
+"            %1$s_%2$s='%3$s'\n"
+"            export %1$s_%2$s\n"
+"            OPT_NAME='%2$s'\n";
+
+static char const zMayArg[]  =
+"            eval %1$s_%2$s${OPT_ELEMENT}=true\n"
+"            export %1$s_%2$s${OPT_ELEMENT}\n"
+"            OPT_ARG_NEEDED=OK\n";
+
+static char const zMustArg[] =
+"            OPT_ARG_NEEDED=YES\n";
+
+static char const zCantArg[] =
+"            eval %1$s_%2$s${OPT_ELEMENT}=true\n"
+"            export %1$s_%2$s${OPT_ELEMENT}\n"
+"            OPT_ARG_NEEDED=NO\n";
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  LONG OPTION PROCESSING
+ *
+ *  Formats for emitting the text for handling long option types
+ */
+static char const zLongOptInit[] =
+"        OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n"
+"        shift\n"
+"        OPT_ARG=\"$1\"\n\n"
+"        case \"${OPT_CODE}\" in *=* )\n"
+"            OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n"
+"            OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n";
+
+static char const zLongOptArg[] =
+"        case \"${OPT_ARG_NEEDED}\" in\n"
+"        NO )\n"
+"            OPT_ARG_VAL=''\n"
+"            ;;\n\n"
+"        YES )\n"
+"            if [ -z \"${OPT_ARG_VAL}\" ]\n"
+"            then\n"
+"                if [ $# -eq 0 ]\n"
+"                then\n"
+"                    echo No argument provided for ${OPT_NAME} option >&2\n"
+"                    echo \"$%s_USAGE_TEXT\"\n"
+"                    exit 1\n"
+"                fi\n\n"
+"                OPT_ARG_VAL=\"${OPT_ARG}\"\n"
+"                shift\n"
+"                OPT_ARG=\"$1\"\n"
+"            fi\n"
+"            ;;\n\n"
+"        OK )\n"
+"            if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n"
+"            then\n"
+"                case \"${OPT_ARG}\" in -* ) ;; * )\n"
+"                    OPT_ARG_VAL=\"${OPT_ARG}\"\n"
+"                    shift\n"
+"                    OPT_ARG=\"$1\" ;; esac\n"
+"            fi\n"
+"            ;;\n"
+"        esac\n";
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  FLAG OPTION PROCESSING
+ *
+ *  Formats for emitting the text for handling flag option types
+ */
+static char const zFlagOptInit[] =
+"        OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n"
+"        OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n";
+
+static char const zFlagOptArg[] =
+"        case \"${OPT_ARG_NEEDED}\" in\n"
+"        NO )\n"
+"            if [ -n \"${OPT_ARG}\" ]\n"
+"            then\n"
+"                OPT_ARG=-\"${OPT_ARG}\"\n"
+"            else\n"
+"                shift\n"
+"                OPT_ARG=\"$1\"\n"
+"            fi\n"
+"            ;;\n\n"
+"        YES )\n"
+"            if [ -n \"${OPT_ARG}\" ]\n"
+"            then\n"
+"                OPT_ARG_VAL=\"${OPT_ARG}\"\n\n"
+"            else\n"
+"                if [ $# -eq 0 ]\n"
+"                then\n"
+"                    echo No argument provided for ${OPT_NAME} option >&2\n"
+"                    echo \"$%s_USAGE_TEXT\"\n"
+"                    exit 1\n"
+"                fi\n"
+"                shift\n"
+"                OPT_ARG_VAL=\"$1\"\n"
+"            fi\n\n"
+"            shift\n"
+"            OPT_ARG=\"$1\"\n"
+"            ;;\n\n"
+"        OK )\n"
+"            if [ -n \"${OPT_ARG}\" ]\n"
+"            then\n"
+"                OPT_ARG_VAL=\"${OPT_ARG}\"\n"
+"                shift\n"
+"                OPT_ARG=\"$1\"\n\n"
+"            else\n"
+"                shift\n"
+"                if [ $# -gt 0 ]\n"
+"                then\n"
+"                    case \"$1\" in -* ) ;; * )\n"
+"                        OPT_ARG_VAL=\"$1\"\n"
+"                        shift ;; esac\n"
+"                    OPT_ARG=\"$1\"\n"
+"                fi\n"
+"            fi\n"
+"            ;;\n"
+"        esac\n";
+
+tSCC* pzShell = NULL;
+static char*  pzLeader  = NULL;
+static char*  pzTrailer = NULL;
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+emit_var_text(char const * prog, char const * var, int fdin);
+
+static void
+textToVariable(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD);
+
+static void
+emitUsage(tOptions* pOpts);
+
+static void
+emitSetup(tOptions* pOpts);
+
+static void
+printOptionAction(tOptions* pOpts, tOptDesc* pOptDesc);
+
+static void
+printOptionInaction(tOptions* pOpts, tOptDesc* pOptDesc);
+
+static void
+emitFlag(tOptions* pOpts);
+
+static void
+emitMatchExpr(tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts);
+
+static void
+emitLong(tOptions* pOpts);
+
+static void
+openOutput(char const* pzFile);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*=export_func  optionParseShell
+ * private:
+ *
+ * what:  Decipher a boolean value
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ *
+ * doc:
+ *  Emit a shell script that will parse the command line options.
+=*/
+void
+optionParseShell(tOptions* pOpts)
+{
+    /*
+     *  Check for our SHELL option now.
+     *  IF the output file contains the "#!" magic marker,
+     *  it will override anything we do here.
+     */
+    if (HAVE_GENSHELL_OPT(SHELL))
+        pzShell = GENSHELL_OPT_ARG(SHELL);
+
+    else if (! ENABLED_GENSHELL_OPT(SHELL))
+        pzShell = NULL;
+
+    else if ((pzShell = getenv("SHELL")),
+             pzShell == NULL)
+
+        pzShell = POSIX_SHELL;
+
+    /*
+     *  Check for a specified output file
+     */
+    if (HAVE_GENSHELL_OPT(SCRIPT))
+        openOutput(GENSHELL_OPT_ARG(SCRIPT));
+
+    emitUsage(pOpts);
+    emitSetup(pOpts);
+
+    /*
+     *  There are four modes of option processing.
+     */
+    switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
+    case OPTPROC_LONGOPT:
+        fputs(zLoopCase,        stdout);
+
+        fputs(zLongSelection,   stdout);
+        fputs(zLongOptInit,     stdout);
+        emitLong(pOpts);
+        printf(zLongOptArg,     pOpts->pzPROGNAME);
+        fputs(zEndSelection,    stdout);
+
+        fputs(zNoSelection,     stdout);
+        break;
+
+    case 0:
+        fputs(zLoopOnly,        stdout);
+        fputs(zLongOptInit,     stdout);
+        emitLong(pOpts);
+        printf(zLongOptArg,     pOpts->pzPROGNAME);
+        break;
+
+    case OPTPROC_SHORTOPT:
+        fputs(zLoopCase,        stdout);
+
+        fputs(zFlagSelection,   stdout);
+        fputs(zFlagOptInit,     stdout);
+        emitFlag(pOpts);
+        printf(zFlagOptArg,     pOpts->pzPROGNAME);
+        fputs(zEndSelection,    stdout);
+
+        fputs(zNoSelection,     stdout);
+        break;
+
+    case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
+        fputs(zLoopCase,        stdout);
+
+        fputs(zLongSelection,   stdout);
+        fputs(zLongOptInit,     stdout);
+        emitLong(pOpts);
+        printf(zLongOptArg,     pOpts->pzPROGNAME);
+        fputs(zEndSelection,    stdout);
+
+        fputs(zFlagSelection,   stdout);
+        fputs(zFlagOptInit,     stdout);
+        emitFlag(pOpts);
+        printf(zFlagOptArg,     pOpts->pzPROGNAME);
+        fputs(zEndSelection,    stdout);
+
+        fputs(zNoSelection,     stdout);
+        break;
+    }
+
+    printf(zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker);
+    if ((pzTrailer != NULL) && (*pzTrailer != '\0'))
+        fputs(pzTrailer, stdout);
+    else if (ENABLED_GENSHELL_OPT(SHELL))
+        printf("\nenv | grep '^%s_'\n", pOpts->pzPROGNAME);
+
+    fflush(stdout);
+    fchmod(STDOUT_FILENO, 0755);
+    fclose(stdout);
+    if (ferror(stdout)) {
+        fputs(zOutputFail, stderr);
+        exit(EXIT_FAILURE);
+    }
+}
+
+#ifdef HAVE_WORKING_FORK
+static void
+emit_var_text(char const * prog, char const * var, int fdin)
+{
+    FILE * fp   = fdopen(fdin, "r" FOPEN_BINARY_FLAG);
+    int    nlct = 0; /* defer newlines and skip trailing ones */
+
+    printf("%s_%s_TEXT='", prog, var);
+    if (fp == NULL)
+        goto skip_text;
+
+    for (;;) {
+        int  ch = fgetc(fp);
+        switch (ch) {
+
+        case '\n':
+            nlct++;
+            break;
+
+        case '\'':
+            while (nlct > 0) {
+                fputc('\n', stdout);
+                nlct--;
+            }
+            fputs("'\\''", stdout);
+            break;
+
+        case EOF:
+            goto endCharLoop;
+
+        default:
+            while (nlct > 0) {
+                fputc('\n', stdout);
+                nlct--;
+            }
+            fputc(ch, stdout);
+            break;
+        }
+    } endCharLoop:;
+
+    fclose(fp);
+
+skip_text:
+
+    fputs("'\n\n", stdout);
+}
+
+#endif
+
+/*
+ *  The purpose of this function is to assign "long usage", short usage
+ *  and version information to a shell variable.  Rather than wind our
+ *  way through all the logic necessary to emit the text directly, we
+ *  fork(), have our child process emit the text the normal way and
+ *  capture the output in the parent process.
+ */
+static void
+textToVariable(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD)
+{
+#   define _TT_(n) static char const z ## n [] = #n;
+    TEXTTO_TABLE
+#   undef _TT_
+#   define _TT_(n) z ## n ,
+      static char const * apzTTNames[] = { TEXTTO_TABLE };
+#   undef _TT_
+
+#if ! defined(HAVE_WORKING_FORK)
+    printf("%1$s_%2$s_TEXT='no %2$s text'\n",
+           pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
+#else
+    int  pipeFd[2];
+
+    fflush(stdout);
+    fflush(stderr);
+
+    if (pipe(pipeFd) != 0) {
+        fprintf(stderr, zBadPipe, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    switch (fork()) {
+    case -1:
+        fprintf(stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
+        exit(EXIT_FAILURE);
+        break;
+
+    case 0:
+        /*
+         * Send both stderr and stdout to the pipe.  No matter which
+         * descriptor is used, we capture the output on the read end.
+         */
+        dup2(pipeFd[1], STDERR_FILENO);
+        dup2(pipeFd[1], STDOUT_FILENO);
+        close(pipeFd[0]);
+
+        switch (whichVar) {
+        case TT_LONGUSAGE:
+            (*(pOpts->pUsageProc))(pOpts, EXIT_SUCCESS);
+            /* NOTREACHED */
+
+        case TT_USAGE:
+            (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+
+        case TT_VERSION:
+            if (pOD->fOptState & OPTST_ALLOC_ARG) {
+                AGFREE(pOD->optArg.argString);
+                pOD->fOptState &= ~OPTST_ALLOC_ARG;
+            }
+            pOD->optArg.argString = "c";
+            optionPrintVersion(pOpts, pOD);
+            /* NOTREACHED */
+
+        default:
+            exit(EXIT_FAILURE);
+        }
+
+    default:
+        close(pipeFd[1]);
+    }
+
+    emit_var_text(pOpts->pzPROGNAME, apzTTNames[whichVar], pipeFd[0]);
+#endif
+}
+
+
+static void
+emitUsage(tOptions* pOpts)
+{
+    char zTimeBuf[AO_NAME_SIZE];
+
+    /*
+     *  First, switch stdout to the output file name.
+     *  Then, change the program name to the one defined
+     *  by the definitions (rather than the current
+     *  executable name).  Down case the upper cased name.
+     */
+    if (pzLeader != NULL)
+        fputs(pzLeader, stdout);
+
+    {
+        tSCC    zStdout[] = "stdout";
+        tCC*    pzOutName;
+
+        {
+            time_t    curTime = time(NULL);
+            struct tm*  pTime = localtime(&curTime);
+            strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
+        }
+
+        if (HAVE_GENSHELL_OPT(SCRIPT))
+             pzOutName = GENSHELL_OPT_ARG(SCRIPT);
+        else pzOutName = zStdout;
+
+        if ((pzLeader == NULL) && (pzShell != NULL))
+            printf("#! %s\n", pzShell);
+
+        printf(zPreamble, zStartMarker, pzOutName, zTimeBuf);
+    }
+
+    printf(zEndPreamble, pOpts->pzPROGNAME);
+
+    /*
+     *  Get a copy of the original program name in lower case and
+     *  fill in an approximation of the program name from it.
+     */
+    {
+        char *       pzPN = zTimeBuf;
+        char const * pz   = pOpts->pzPROGNAME;
+        char **      pp;
+
+        for (;;) {
+            if ((*pzPN++ = tolower(*pz++)) == '\0')
+                break;
+        }
+
+        pp = (char **)(void *)&(pOpts->pzProgPath);
+        *pp = zTimeBuf;
+        pp  = (char **)(void *)&(pOpts->pzProgName);
+        *pp = zTimeBuf;
+    }
+
+    textToVariable(pOpts, TT_LONGUSAGE, NULL);
+    textToVariable(pOpts, TT_USAGE,     NULL);
+
+    {
+        tOptDesc* pOptDesc = pOpts->pOptDesc;
+        int       optionCt = pOpts->optCt;
+
+        for (;;) {
+            if (pOptDesc->pOptProc == optionPrintVersion) {
+                textToVariable(pOpts, TT_VERSION, pOptDesc);
+                break;
+            }
+
+            if (--optionCt <= 0)
+                break;
+            pOptDesc++;
+        }
+    }
+}
+
+
+static void
+emitSetup(tOptions* pOpts)
+{
+    tOptDesc* pOptDesc = pOpts->pOptDesc;
+    int       optionCt = pOpts->presetOptCt;
+    char const* pzFmt;
+    char const* pzDefault;
+
+    for (;optionCt > 0; pOptDesc++, --optionCt) {
+        char zVal[16];
+
+        /*
+         *  Options that are either usage documentation or are compiled out
+         *  are not to be processed.
+         */
+        if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
+            continue;
+
+        if (pOptDesc->optMaxCt > 1)
+             pzFmt = zMultiDef;
+        else pzFmt = zSingleDef;
+
+        /*
+         *  IF this is an enumeration/bitmask option, then convert the value
+         *  to a string before printing the default value.
+         */
+        switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
+        case OPARG_TYPE_ENUMERATION:
+            (*(pOptDesc->pOptProc))(OPTPROC_EMIT_SHELL, pOptDesc );
+            pzDefault = pOptDesc->optArg.argString;
+            break;
+
+        /*
+         *  Numeric and membership bit options are just printed as a number.
+         */
+        case OPARG_TYPE_NUMERIC:
+            snprintf(zVal, sizeof(zVal), "%d",
+                     (int)pOptDesc->optArg.argInt);
+            pzDefault = zVal;
+            break;
+
+        case OPARG_TYPE_MEMBERSHIP:
+            snprintf(zVal, sizeof(zVal), "%lu",
+                     (unsigned long)pOptDesc->optArg.argIntptr);
+            pzDefault = zVal;
+            break;
+
+        case OPARG_TYPE_BOOLEAN:
+            pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
+            break;
+
+        default:
+            if (pOptDesc->optArg.argString == NULL) {
+                if (pzFmt == zSingleDef)
+                    pzFmt = zSingleNoDef;
+                pzDefault = NULL;
+            }
+            else
+                pzDefault = pOptDesc->optArg.argString;
+        }
+
+        printf(pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault);
+    }
+}
+
+
+static void
+printOptionAction(tOptions* pOpts, tOptDesc* pOptDesc)
+{
+    if (pOptDesc->pOptProc == optionPrintVersion)
+        printf(zTextExit, pOpts->pzPROGNAME, "VERSION");
+
+    else if (pOptDesc->pOptProc == optionPagedUsage)
+        printf(zPagedUsageExit, pOpts->pzPROGNAME);
+
+    else if (pOptDesc->pOptProc == optionLoadOpt) {
+        printf(zCmdFmt, "echo 'Warning:  Cannot load options files' >&2");
+        printf(zCmdFmt, "OPT_ARG_NEEDED=YES");
+
+    } else if (pOptDesc->pz_NAME == NULL) {
+
+        if (pOptDesc->pOptProc == NULL) {
+            printf(zCmdFmt, "echo 'Warning:  Cannot save options files' "
+                    ">&2");
+            printf(zCmdFmt, "OPT_ARG_NEEDED=OK");
+        } else
+            printf(zTextExit, pOpts->pzPROGNAME, "LONGUSAGE");
+
+    } else {
+        if (pOptDesc->optMaxCt == 1)
+            printf(zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+        else {
+            if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
+                printf(zCountTest, pOpts->pzPROGNAME,
+                       pOptDesc->pz_NAME, pOptDesc->optMaxCt);
+
+            printf(zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+        }
+
+        /*
+         *  Fix up the args.
+         */
+        if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
+            printf(zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+
+        } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
+            printf(zMayArg,  pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+
+        } else {
+            fputs(zMustArg, stdout);
+        }
+    }
+    fputs(zOptionEndSelect, stdout);
+}
+
+
+static void
+printOptionInaction(tOptions* pOpts, tOptDesc* pOptDesc)
+{
+    if (pOptDesc->pOptProc == optionLoadOpt) {
+        printf(zCmdFmt, "echo 'Warning:  Cannot suppress the loading of "
+                "options files' >&2");
+
+    } else if (pOptDesc->optMaxCt == 1)
+        printf(zNoSingleArg, pOpts->pzPROGNAME,
+               pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
+    else
+        printf(zNoMultiArg, pOpts->pzPROGNAME,
+               pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
+
+    printf(zCmdFmt, "OPT_ARG_NEEDED=NO");
+    fputs(zOptionEndSelect, stdout);
+}
+
+
+static void
+emitFlag(tOptions* pOpts)
+{
+    tOptDesc* pOptDesc = pOpts->pOptDesc;
+    int       optionCt = pOpts->optCt;
+
+    fputs(zOptionCase, stdout);
+
+    for (;optionCt > 0; pOptDesc++, --optionCt) {
+
+        if (SKIP_OPT(pOptDesc))
+            continue;
+
+        if (IS_GRAPHIC_CHAR(pOptDesc->optValue)) {
+            printf(zOptionFlag, pOptDesc->optValue);
+            printOptionAction(pOpts, pOptDesc);
+        }
+    }
+    printf(zOptionUnknown, "flag", pOpts->pzPROGNAME);
+}
+
+
+/*
+ *  Emit the match text for a long option
+ */
+static void
+emitMatchExpr(tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts)
+{
+    tOptDesc* pOD = pOpts->pOptDesc;
+    int       oCt = pOpts->optCt;
+    int       min = 1;
+    char      zName[ 256 ];
+    char*     pz  = zName;
+
+    for (;;) {
+        int matchCt = 0;
+
+        /*
+         *  Omit the current option, Documentation opts and compiled out opts.
+         */
+        if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
+            if (--oCt <= 0)
+                break;
+            pOD++;
+            continue;
+        }
+
+        /*
+         *  Check each character of the name case insensitively.
+         *  They must not be the same.  They cannot be, because it would
+         *  not compile correctly if they were.
+         */
+        while (  toupper(pOD->pz_Name[matchCt])
+              == toupper(pzMatchName[matchCt]))
+            matchCt++;
+
+        if (matchCt > min)
+            min = matchCt;
+
+        /*
+         *  Check the disablement name, too.
+         */
+        if (pOD->pz_DisableName != NULL) {
+            matchCt = 0;
+            while (  toupper(pOD->pz_DisableName[matchCt])
+                  == toupper(pzMatchName[matchCt]))
+                matchCt++;
+            if (matchCt > min)
+                min = matchCt;
+        }
+        if (--oCt <= 0)
+            break;
+        pOD++;
+    }
+
+    /*
+     *  IF the 'min' is all or one short of the name length,
+     *  THEN the entire string must be matched.
+     */
+    if (  (pzMatchName[min  ] == NUL)
+       || (pzMatchName[min+1] == NUL) )
+        printf(zOptionFullName, pzMatchName);
+
+    else {
+        int matchCt = 0;
+        for (; matchCt <= min; matchCt++)
+            *pz++ = pzMatchName[matchCt];
+
+        for (;;) {
+            *pz = NUL;
+            printf(zOptionPartName, zName);
+            *pz++ = pzMatchName[matchCt++];
+            if (pzMatchName[matchCt] == NUL) {
+                *pz = NUL;
+                printf(zOptionFullName, zName);
+                break;
+            }
+        }
+    }
+}
+
+
+/*
+ *  Emit GNU-standard long option handling code
+ */
+static void
+emitLong(tOptions* pOpts)
+{
+    tOptDesc* pOD = pOpts->pOptDesc;
+    int       ct  = pOpts->optCt;
+
+    fputs(zOptionCase, stdout);
+
+    /*
+     *  do each option, ...
+     */
+    do  {
+        /*
+         *  Documentation & compiled-out options
+         */
+        if (SKIP_OPT(pOD))
+            continue;
+
+        emitMatchExpr(pOD->pz_Name, pOD, pOpts);
+        printOptionAction(pOpts, pOD);
+
+        /*
+         *  Now, do the same thing for the disablement version of the option.
+         */
+        if (pOD->pz_DisableName != NULL) {
+            emitMatchExpr(pOD->pz_DisableName, pOD, pOpts);
+            printOptionInaction(pOpts, pOD);
+        }
+    } while (pOD++, --ct > 0);
+
+    printf(zOptionUnknown, "option", pOpts->pzPROGNAME);
+}
+
+
+static void
+openOutput(char const* pzFile)
+{
+    FILE* fp;
+    char* pzData = NULL;
+    struct stat stbf;
+
+    do  {
+        char*    pzScan;
+        size_t sizeLeft;
+
+        /*
+         *  IF we cannot stat the file,
+         *  THEN assume we are creating a new file.
+         *       Skip the loading of the old data.
+         */
+        if (stat(pzFile, &stbf) != 0)
+            break;
+
+        /*
+         *  The file must be a regular file
+         */
+        if (! S_ISREG(stbf.st_mode)) {
+            fprintf(stderr, zNotFile, pzFile);
+            exit(EXIT_FAILURE);
+        }
+
+        pzData = AGALOC(stbf.st_size + 1, "file data");
+        fp = fopen(pzFile, "r" FOPEN_BINARY_FLAG);
+
+        sizeLeft = (unsigned)stbf.st_size;
+        pzScan   = pzData;
+
+        /*
+         *  Read in all the data as fast as our OS will let us.
+         */
+        for (;;) {
+            int inct = fread((void*)pzScan, (size_t)1, sizeLeft, fp);
+            if (inct == 0)
+                break;
+
+            pzScan   += inct;
+            sizeLeft -= inct;
+
+            if (sizeLeft == 0)
+                break;
+        }
+
+        /*
+         *  NUL-terminate the leader and look for the trailer
+         */
+        *pzScan = '\0';
+        fclose(fp);
+        pzScan  = strstr(pzData, zStartMarker);
+        if (pzScan == NULL) {
+            pzTrailer = pzData;
+            break;
+        }
+
+        *(pzScan++) = NUL;
+        pzScan  = strstr(pzScan, zTrailerMarker);
+        if (pzScan == NULL) {
+            pzTrailer = pzData;
+            break;
+        }
+
+        /*
+         *  Check to see if the data contains our marker.
+         *  If it does, then we will skip over it
+         */
+        pzTrailer = pzScan + sizeof(zTrailerMarker) - 1;
+        pzLeader  = pzData;
+    } while (AG_FALSE);
+
+    if (freopen(pzFile, "w" FOPEN_BINARY_FLAG, stdout) != stdout) {
+        fprintf(stderr, zFreopenFail, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+}
+
+
+/*=export_func genshelloptUsage
+ * private:
+ * what: The usage function for the genshellopt generated program
+ *
+ * arg:  + tOptions* + pOpts    + program options descriptor +
+ * arg:  + int       + exitCode + usage text type to produce +
+ *
+ * doc:
+ *  This function is used to create the usage strings for the option
+ *  processing shell script code.  Two child processes are spawned
+ *  each emitting the usage text in either the short (error exit)
+ *  style or the long style.  The generated program will capture this
+ *  and create shell script variables containing the two types of text.
+=*/
+void
+genshelloptUsage(tOptions * pOpts, int exitCode)
+{
+#if ! defined(HAVE_WORKING_FORK)
+    optionUsage(pOpts, exitCode);
+#else
+    /*
+     *  IF not EXIT_SUCCESS,
+     *  THEN emit the short form of usage.
+     */
+    if (exitCode != EXIT_SUCCESS)
+        optionUsage(pOpts, exitCode);
+    fflush(stderr);
+    fflush(stdout);
+    if (ferror(stdout) || ferror(stderr))
+        exit(EXIT_FAILURE);
+
+    option_usage_fp = stdout;
+
+    /*
+     *  First, print our usage
+     */
+    switch (fork()) {
+    case -1:
+        optionUsage(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+
+    case 0:
+        pagerState = PAGER_STATE_CHILD;
+        optionUsage(pOpts, EXIT_SUCCESS);
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE);
+
+    default:
+    {
+        int  sts;
+        wait(&sts);
+    }
+    }
+
+    /*
+     *  Generate the pzProgName, since optionProcess() normally
+     *  gets it from the command line
+     */
+    {
+        char *  pz;
+        char ** pp = (char **)(void *)&(optionParseShellOptions->pzProgName);
+        AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "program name");
+        *pp = pz;
+        while (*pz != NUL) {
+            *pz = tolower(*pz);
+            pz++;
+        }
+    }
+
+    /*
+     *  Separate the makeshell usage from the client usage
+     */
+    fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
+    fflush(option_usage_fp);
+
+    /*
+     *  Now, print the client usage.
+     */
+    switch (fork()) {
+    case 0:
+        pagerState = PAGER_STATE_CHILD;
+        /*FALLTHROUGH*/
+    case -1:
+        optionUsage(optionParseShellOptions, EXIT_FAILURE);
+
+    default:
+    {
+        int  sts;
+        wait(&sts);
+    }
+    }
+
+    fflush(stdout);
+    if (ferror(stdout)) {
+        fputs(zOutputFail, stderr);
+        exit(EXIT_FAILURE);
+    }
+
+    exit(EXIT_SUCCESS);
+#endif
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/makeshell.c */
diff --git a/libopts/nested.c b/libopts/nested.c
new file mode 100644 (file)
index 0000000..f9f7e7a
--- /dev/null
@@ -0,0 +1,823 @@
+
+/**
+ * \file nested.c
+ *
+ *  Time-stamp:      "2010-08-22 11:17:56 bkorb"
+ *
+ *   Automated Options Nested Values module.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+typedef struct {
+    int     xml_ch;
+    int     xml_len;
+    char    xml_txt[8];
+} xml_xlate_t;
+
+static xml_xlate_t const xml_xlate[] = {
+    { '&', 4, "amp;"  },
+    { '<', 3, "lt;"   },
+    { '>', 3, "gt;"   },
+    { '"', 5, "quot;" },
+    { '\'',5, "apos;" }
+};
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+remove_continuation(char* pzSrc);
+
+static char const*
+scan_q_str(char const* pzTxt);
+
+static tOptionValue*
+add_string(void** pp, char const* pzName, size_t nameLen,
+               char const* pzValue, size_t dataLen);
+
+static tOptionValue*
+add_bool(void** pp, char const* pzName, size_t nameLen,
+         char const* pzValue, size_t dataLen);
+
+static tOptionValue*
+add_number(void** pp, char const* pzName, size_t nameLen,
+           char const* pzValue, size_t dataLen);
+
+static tOptionValue*
+add_nested(void** pp, char const* pzName, size_t nameLen,
+           char* pzValue, size_t dataLen);
+
+static char const *
+scan_name(char const* pzName, tOptionValue* pRes);
+
+static char const*
+scan_xml(char const* pzName, tOptionValue* pRes);
+
+static void
+sort_list(tArgList* pAL);
+/* = = = END-STATIC-FORWARD = = = */
+
+/**
+ *  Backslashes are used for line continuations.  We keep the newline
+ *  characters, but trim out the backslash:
+ */
+static void
+remove_continuation(char* pzSrc)
+{
+    char* pzD;
+
+    do  {
+        while (*pzSrc == '\n')  pzSrc++;
+        pzD = strchr(pzSrc, '\n');
+        if (pzD == NULL)
+            return;
+
+        /*
+         *  pzD has skipped at least one non-newline character and now
+         *  points to a newline character.  It now becomes the source and
+         *  pzD goes to the previous character.
+         */
+        pzSrc = pzD--;
+        if (*pzD != '\\')
+            pzD++;
+    } while (pzD == pzSrc);
+
+    /*
+     *  Start shifting text.
+     */
+    for (;;) {
+        char ch = ((*pzD++) = *(pzSrc++));
+        switch (ch) {
+        case NUL:  return;
+        case '\\':
+            if (*pzSrc == '\n')
+                --pzD; /* rewrite on next iteration */
+        }
+    }
+}
+
+/**
+ *  Find the end of a quoted string, skipping escaped quote characters.
+ */
+static char const*
+scan_q_str(char const* pzTxt)
+{
+    char q = *(pzTxt++); /* remember the type of quote */
+
+    for (;;) {
+        char ch = *(pzTxt++);
+        if (ch == NUL)
+            return pzTxt-1;
+
+        if (ch == q)
+            return pzTxt;
+
+        if (ch == '\\') {
+            ch = *(pzTxt++);
+            /*
+             *  IF the next character is NUL, drop the backslash, too.
+             */
+            if (ch == NUL)
+                return pzTxt - 2;
+
+            /*
+             *  IF the quote character or the escape character were escaped,
+             *  then skip both, as long as the string does not end.
+             */
+            if ((ch == q) || (ch == '\\')) {
+                if (*(pzTxt++) == NUL)
+                    return pzTxt-1;
+            }
+        }
+    }
+}
+
+
+/**
+ *  Associate a name with either a string or no value.
+ */
+static tOptionValue*
+add_string(void** pp, char const* pzName, size_t nameLen,
+               char const* pzValue, size_t dataLen)
+{
+    tOptionValue* pNV;
+    size_t sz = nameLen + dataLen + sizeof(*pNV);
+
+    pNV = AGALOC(sz, "option name/str value pair");
+    if (pNV == NULL)
+        return NULL;
+
+    if (pzValue == NULL) {
+        pNV->valType = OPARG_TYPE_NONE;
+        pNV->pzName = pNV->v.strVal;
+
+    } else {
+        pNV->valType = OPARG_TYPE_STRING;
+        if (dataLen > 0) {
+            char const * pzSrc = pzValue;
+            char * pzDst = pNV->v.strVal;
+            int    ct    = dataLen;
+            do  {
+                int ch = *(pzSrc++) & 0xFF;
+                if (ch == NUL) goto data_copy_done;
+                if (ch == '&')
+                    ch = get_special_char(&pzSrc, &ct);
+                *(pzDst++) = ch;
+            } while (--ct > 0);
+        data_copy_done:
+            *pzDst = NUL;
+
+        } else {
+            pNV->v.strVal[0] = NUL;
+        }
+
+        pNV->pzName = pNV->v.strVal + dataLen + 1;
+    }
+
+    memcpy(pNV->pzName, pzName, nameLen);
+    pNV->pzName[ nameLen ] = NUL;
+    addArgListEntry(pp, pNV);
+    return pNV;
+}
+
+/**
+ *  Associate a name with either a string or no value.
+ */
+static tOptionValue*
+add_bool(void** pp, char const* pzName, size_t nameLen,
+         char const* pzValue, size_t dataLen)
+{
+    tOptionValue* pNV;
+    size_t sz = nameLen + sizeof(*pNV) + 1;
+
+    pNV = AGALOC(sz, "option name/bool value pair");
+    if (pNV == NULL)
+        return NULL;
+    while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) {
+        dataLen--; pzValue++;
+    }
+    if (dataLen == 0)
+        pNV->v.boolVal = 0;
+
+    else if (IS_DEC_DIGIT_CHAR(*pzValue))
+        pNV->v.boolVal = atoi(pzValue);
+
+    else pNV->v.boolVal = ! IS_FALSE_TYPE_CHAR(*pzValue);
+
+    pNV->valType = OPARG_TYPE_BOOLEAN;
+    pNV->pzName = (char*)(pNV + 1);
+    memcpy(pNV->pzName, pzName, nameLen);
+    pNV->pzName[ nameLen ] = NUL;
+    addArgListEntry(pp, pNV);
+    return pNV;
+}
+
+/**
+ *  Associate a name with either a string or no value.
+ */
+static tOptionValue*
+add_number(void** pp, char const* pzName, size_t nameLen,
+           char const* pzValue, size_t dataLen)
+{
+    tOptionValue* pNV;
+    size_t sz = nameLen + sizeof(*pNV) + 1;
+
+    pNV = AGALOC(sz, "option name/bool value pair");
+    if (pNV == NULL)
+        return NULL;
+    while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) {
+        dataLen--; pzValue++;
+    }
+    if (dataLen == 0)
+        pNV->v.longVal = 0;
+    else
+        pNV->v.longVal = strtol(pzValue, 0, 0);
+
+    pNV->valType = OPARG_TYPE_NUMERIC;
+    pNV->pzName  = (char*)(pNV + 1);
+    memcpy(pNV->pzName, pzName, nameLen);
+    pNV->pzName[ nameLen ] = NUL;
+    addArgListEntry(pp, pNV);
+    return pNV;
+}
+
+/**
+ *  Associate a name with either a string or no value.
+ */
+static tOptionValue*
+add_nested(void** pp, char const* pzName, size_t nameLen,
+           char* pzValue, size_t dataLen)
+{
+    tOptionValue* pNV;
+
+    if (dataLen == 0) {
+        size_t sz = nameLen + sizeof(*pNV) + 1;
+        pNV = AGALOC(sz, "empty nested value pair");
+        if (pNV == NULL)
+            return NULL;
+        pNV->v.nestVal = NULL;
+        pNV->valType = OPARG_TYPE_HIERARCHY;
+        pNV->pzName = (char*)(pNV + 1);
+        memcpy(pNV->pzName, pzName, nameLen);
+        pNV->pzName[ nameLen ] = NUL;
+
+    } else {
+        pNV = optionLoadNested(pzValue, pzName, nameLen);
+    }
+
+    if (pNV != NULL)
+        addArgListEntry(pp, pNV);
+
+    return pNV;
+}
+
+/**
+ *  We have an entry that starts with a name.  Find the end of it, cook it
+ *  (if called for) and create the name/value association.
+ */
+static char const *
+scan_name(char const* pzName, tOptionValue* pRes)
+{
+    tOptionValue* pNV;
+    char const * pzScan = pzName+1; /* we know first char is a name char */
+    char const * pzVal;
+    size_t       nameLen = 1;
+    size_t       dataLen = 0;
+
+    /*
+     *  Scan over characters that name a value.  These names may not end
+     *  with a colon, but they may contain colons.
+     */
+    while (IS_VALUE_NAME_CHAR(*pzScan))   { pzScan++; nameLen++; }
+    if (pzScan[-1] == ':')                { pzScan--; nameLen--; }
+    while (IS_HORIZ_WHITE_CHAR(*pzScan))    pzScan++;
+
+ re_switch:
+
+    switch (*pzScan) {
+    case '=':
+    case ':':
+        while (IS_HORIZ_WHITE_CHAR((int)*++pzScan))  ;
+        if ((*pzScan == '=') || (*pzScan == ':'))
+            goto default_char;
+        goto re_switch;
+
+    case '\n':
+    case ',':
+        pzScan++;
+        /* FALLTHROUGH */
+
+    case NUL:
+        add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
+        break;
+
+    case '"':
+    case '\'':
+        pzVal = pzScan;
+        pzScan = scan_q_str(pzScan);
+        dataLen = pzScan - pzVal;
+        pNV = add_string(&(pRes->v.nestVal), pzName, nameLen, pzVal,
+                             dataLen);
+        if ((pNV != NULL) && (option_load_mode == OPTION_LOAD_COOKED))
+            ao_string_cook(pNV->v.strVal, NULL);
+        break;
+
+    default:
+    default_char:
+        /*
+         *  We have found some strange text value.  It ends with a newline
+         *  or a comma.
+         */
+        pzVal = pzScan;
+        for (;;) {
+            char ch = *(pzScan++);
+            switch (ch) {
+            case NUL:
+                pzScan--;
+                dataLen = pzScan - pzVal;
+                goto string_done;
+                /* FALLTHROUGH */
+
+            case '\n':
+                if (   (pzScan > pzVal + 2)
+                    && (pzScan[-2] == '\\')
+                    && (pzScan[ 0] != NUL))
+                    continue;
+                /* FALLTHROUGH */
+
+            case ',':
+                dataLen = (pzScan - pzVal) - 1;
+            string_done:
+                pNV = add_string(&(pRes->v.nestVal), pzName, nameLen,
+                                     pzVal, dataLen);
+                if (pNV != NULL)
+                    remove_continuation(pNV->v.strVal);
+                goto leave_scan_name;
+            }
+        }
+        break;
+    } leave_scan_name:;
+
+    return pzScan;
+}
+
+/**
+ *  We've found a '<' character.  We ignore this if it is a comment or a
+ *  directive.  If it is something else, then whatever it is we are looking
+ *  at is bogus.  Returning NULL stops processing.
+ */
+static char const*
+scan_xml(char const* pzName, tOptionValue* pRes)
+{
+    size_t nameLen = 1, valLen = 0;
+    char const*   pzScan = ++pzName;
+    char const*   pzVal;
+    tOptionValue  valu;
+    tOptionValue* pNewVal;
+    tOptionLoadMode save_mode = option_load_mode;
+
+    if (! IS_VAR_FIRST_CHAR(*pzName)) {
+        switch (*pzName) {
+        default:
+            pzName = NULL;
+            break;
+
+        case '!':
+            pzName = strstr(pzName, "-->");
+            if (pzName != NULL)
+                pzName += 3;
+            break;
+
+        case '?':
+            pzName = strchr(pzName, '>');
+            if (pzName != NULL)
+                pzName++;
+            break;
+        }
+        return pzName;
+    }
+
+    pzScan++;
+    while (IS_VALUE_NAME_CHAR((int)*pzScan))  { pzScan++; nameLen++; }
+    if (nameLen > 64)
+        return NULL;
+    valu.valType = OPARG_TYPE_STRING;
+
+    switch (*pzScan) {
+    case ' ':
+    case '\t':
+        pzScan = parseAttributes(
+            NULL, (char*)pzScan, &option_load_mode, &valu );
+        if (*pzScan == '>') {
+            pzScan++;
+            break;
+        }
+
+        if (*pzScan != '/') {
+            option_load_mode = save_mode;
+            return NULL;
+        }
+        /* FALLTHROUGH */
+
+    case '/':
+        if (*++pzScan != '>') {
+            option_load_mode = save_mode;
+            return NULL;
+        }
+        add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
+        option_load_mode = save_mode;
+        return pzScan+1;
+
+    default:
+        option_load_mode = save_mode;
+        return NULL;
+
+    case '>':
+        pzScan++;
+        break;
+    }
+
+    pzVal = pzScan;
+
+    {
+        char z[68];
+        char* pzD = z;
+        int  ct = nameLen;
+        char const* pzS = pzName;
+
+        *(pzD++) = '<';
+        *(pzD++) = '/';
+
+        do  {
+            *(pzD++) = *(pzS++);
+        } while (--ct > 0);
+        *(pzD++) = '>';
+        *pzD = NUL;
+
+        pzScan = strstr(pzScan, z);
+        if (pzScan == NULL) {
+            option_load_mode = save_mode;
+            return NULL;
+        }
+        valLen = (pzScan - pzVal);
+        pzScan += nameLen + 3;
+        while (IS_WHITESPACE_CHAR(*pzScan))  pzScan++;
+    }
+
+    switch (valu.valType) {
+    case OPARG_TYPE_NONE:
+        add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
+        break;
+
+    case OPARG_TYPE_STRING:
+        pNewVal = add_string(
+            &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
+
+        if (option_load_mode == OPTION_LOAD_KEEP)
+            break;
+        mungeString(pNewVal->v.strVal, option_load_mode);
+        break;
+
+    case OPARG_TYPE_BOOLEAN:
+        add_bool(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
+        break;
+
+    case OPARG_TYPE_NUMERIC:
+        add_number(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
+        break;
+
+    case OPARG_TYPE_HIERARCHY:
+    {
+        char* pz = AGALOC(valLen+1, "hierarchical scan");
+        if (pz == NULL)
+            break;
+        memcpy(pz, pzVal, valLen);
+        pz[valLen] = NUL;
+        add_nested(&(pRes->v.nestVal), pzName, nameLen, pz, valLen);
+        AGFREE(pz);
+        break;
+    }
+
+    case OPARG_TYPE_ENUMERATION:
+    case OPARG_TYPE_MEMBERSHIP:
+    default:
+        break;
+    }
+
+    option_load_mode = save_mode;
+    return pzScan;
+}
+
+
+/**
+ *  Deallocate a list of option arguments.  This must have been gotten from
+ *  a hierarchical option argument, not a stacked list of strings.  It is
+ *  an internal call, so it is not validated.  The caller is responsible for
+ *  knowing what they are doing.
+ */
+LOCAL void
+unload_arg_list(tArgList* pAL)
+{
+    int ct = pAL->useCt;
+    tCC** ppNV = pAL->apzArgs;
+
+    while (ct-- > 0) {
+        tOptionValue* pNV = (tOptionValue*)(void*)*(ppNV++);
+        if (pNV->valType == OPARG_TYPE_HIERARCHY)
+            unload_arg_list(pNV->v.nestVal);
+        AGFREE(pNV);
+    }
+
+    AGFREE((void*)pAL);
+}
+
+/*=export_func  optionUnloadNested
+ *
+ * what:  Deallocate the memory for a nested value
+ * arg:   + tOptionValue const * + pOptVal + the hierarchical value +
+ *
+ * doc:
+ *  A nested value needs to be deallocated.  The pointer passed in should
+ *  have been gotten from a call to @code{configFileLoad()} (See
+ *  @pxref{libopts-configFileLoad}).
+=*/
+void
+optionUnloadNested(tOptionValue const * pOV)
+{
+    if (pOV == NULL) return;
+    if (pOV->valType != OPARG_TYPE_HIERARCHY) {
+        errno = EINVAL;
+        return;
+    }
+
+    unload_arg_list(pOV->v.nestVal);
+
+    AGFREE((void*)pOV);
+}
+
+/**
+ *  This is a _stable_ sort.  The entries are sorted alphabetically,
+ *  but within entries of the same name the ordering is unchanged.
+ *  Typically, we also hope the input is sorted.
+ */
+static void
+sort_list(tArgList* pAL)
+{
+    int ix;
+    int lm = pAL->useCt;
+
+    /*
+     *  This loop iterates "useCt" - 1 times.
+     */
+    for (ix = 0; ++ix < lm;) {
+        int iy = ix-1;
+        tOptionValue* pNewNV = (tOptionValue*)(void*)(pAL->apzArgs[ix]);
+        tOptionValue* pOldNV = (tOptionValue*)(void*)(pAL->apzArgs[iy]);
+
+        /*
+         *  For as long as the new entry precedes the "old" entry,
+         *  move the old pointer.  Stop before trying to extract the
+         *  "-1" entry.
+         */
+        while (strcmp(pOldNV->pzName, pNewNV->pzName) > 0) {
+            pAL->apzArgs[iy+1] = (void*)pOldNV;
+            pOldNV = (tOptionValue*)(void*)(pAL->apzArgs[--iy]);
+            if (iy < 0)
+                break;
+        }
+
+        /*
+         *  Always store the pointer.  Sometimes it is redundant,
+         *  but the redundancy is cheaper than a test and branch sequence.
+         */
+        pAL->apzArgs[iy+1] = (void*)pNewNV;
+    }
+}
+
+/* optionLoadNested
+ * private:
+ *
+ * what:  parse a hierarchical option argument
+ * arg:   + char const*     + pzTxt   + the text to scan +
+ * arg:   + char const*     + pzName  + the name for the text +
+ * arg:   + size_t          + nameLen + the length of "name"  +
+ *
+ * ret_type:  tOptionValue*
+ * ret_desc:  An allocated, compound value structure
+ *
+ * doc:
+ *  A block of text represents a series of values.  It may be an
+ *  entire configuration file, or it may be an argument to an
+ *  option that takes a hierarchical value.
+ */
+LOCAL tOptionValue*
+optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen)
+{
+    tOptionValue* pRes;
+
+    /*
+     *  Make sure we have some data and we have space to put what we find.
+     */
+    if (pzTxt == NULL) {
+        errno = EINVAL;
+        return NULL;
+    }
+    while (IS_WHITESPACE_CHAR(*pzTxt))  pzTxt++;
+    if (*pzTxt == NUL) {
+        errno = ENOENT;
+        return NULL;
+    }
+    pRes = AGALOC(sizeof(*pRes) + nameLen + 1, "nested args");
+    if (pRes == NULL) {
+        errno = ENOMEM;
+        return NULL;
+    }
+    pRes->valType   = OPARG_TYPE_HIERARCHY;
+    pRes->pzName    = (char*)(pRes + 1);
+    memcpy(pRes->pzName, pzName, nameLen);
+    pRes->pzName[nameLen] = NUL;
+
+    {
+        tArgList * pAL = AGALOC(sizeof(*pAL), "nested arg list");
+        if (pAL == NULL) {
+            AGFREE(pRes);
+            return NULL;
+        }
+
+        pRes->v.nestVal = pAL;
+        pAL->useCt   = 0;
+        pAL->allocCt = MIN_ARG_ALLOC_CT;
+    }
+
+    /*
+     *  Scan until we hit a NUL.
+     */
+    do  {
+        while (IS_WHITESPACE_CHAR((int)*pzTxt))  pzTxt++;
+        if (IS_VAR_FIRST_CHAR((int)*pzTxt)) {
+            pzTxt = scan_name(pzTxt, pRes);
+        }
+        else switch (*pzTxt) {
+        case NUL: goto scan_done;
+        case '<': pzTxt = scan_xml(pzTxt, pRes);
+                  if (pzTxt == NULL) goto woops;
+                  if (*pzTxt == ',') pzTxt++;     break;
+        case '#': pzTxt = strchr(pzTxt, '\n');  break;
+        default:  goto woops;
+        }
+    } while (pzTxt != NULL); scan_done:;
+
+    {
+        tArgList * al = pRes->v.nestVal;
+        if (al->useCt != 0)
+            sort_list(al);
+    }
+
+    return pRes;
+
+ woops:
+    AGFREE(pRes->v.nestVal);
+    AGFREE(pRes);
+    return NULL;
+}
+
+/*=export_func  optionNestedVal
+ * private:
+ *
+ * what:  parse a hierarchical option argument
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Nested value was found on the command line
+=*/
+void
+optionNestedVal(tOptions* pOpts, tOptDesc* pOD)
+{
+    if (pOpts < OPTPROC_EMIT_LIMIT)
+        return;
+
+    if (pOD->fOptState & OPTST_RESET) {
+        tArgList* pAL = pOD->optCookie;
+        int       ct;
+        tCC **    av;
+
+        if (pAL == NULL)
+            return;
+        ct = pAL->useCt;
+        av = pAL->apzArgs;
+
+        while (--ct >= 0) {
+            void * p = (void *)*(av++);
+            optionUnloadNested((tOptionValue const *)p);
+        }
+
+        AGFREE(pOD->optCookie);
+
+    } else {
+        tOptionValue* pOV = optionLoadNested(
+            pOD->optArg.argString, pOD->pz_Name, strlen(pOD->pz_Name));
+
+        if (pOV != NULL)
+            addArgListEntry(&(pOD->optCookie), (void*)pOV);
+    }
+}
+
+/*
+ * get_special_char
+ */
+LOCAL int
+get_special_char(char const ** ppz, int * ct)
+{
+    char const * pz = *ppz;
+
+    if (*ct < 3)
+        return '&';
+
+    if (*pz == '#') {
+        int base = 10;
+        int retch;
+
+        pz++;
+        if (*pz == 'x') {
+            base = 16;
+            pz++;
+        }
+        retch = (int)strtoul(pz, (char **)&pz, base);
+        if (*pz != ';')
+            return '&';
+        base = ++pz - *ppz;
+        if (base > *ct)
+            return '&';
+
+        *ct -= base;
+        *ppz = pz;
+        return retch;
+    }
+
+    {
+        int ctr = sizeof(xml_xlate) / sizeof(xml_xlate[0]);
+        xml_xlate_t const * xlatp = xml_xlate;
+
+        for (;;) {
+            if (  (*ct >= xlatp->xml_len)
+               && (strncmp(pz, xlatp->xml_txt, xlatp->xml_len) == 0)) {
+                *ppz += xlatp->xml_len;
+                *ct  -= xlatp->xml_len;
+                return xlatp->xml_ch;
+            }
+
+            if (--ctr <= 0)
+                break;
+            xlatp++;
+        }
+    }
+    return '&';
+}
+
+/*
+ * emit_special_char
+ */
+LOCAL void
+emit_special_char(FILE * fp, int ch)
+{
+    int ctr = sizeof(xml_xlate) / sizeof(xml_xlate[0]);
+    xml_xlate_t const * xlatp = xml_xlate;
+
+    putc('&', fp);
+    for (;;) {
+        if (ch == xlatp->xml_ch) {
+            fputs(xlatp->xml_txt, fp);
+            return;
+        }
+        if (--ctr <= 0)
+            break;
+        xlatp++;
+    }
+    fprintf(fp, "#x%02X;", (ch & 0xFF));
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/nested.c */
diff --git a/libopts/numeric.c b/libopts/numeric.c
new file mode 100644 (file)
index 0000000..ff6b2a5
--- /dev/null
@@ -0,0 +1,169 @@
+
+/**
+ * \file numeric.c
+ *
+ *  Time-stamp:      "2011-03-25 16:26:10 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*=export_func  optionShowRange
+ * private:
+ *
+ * what:  
+ * arg:   + tOptions* + pOpts     + program options descriptor  +
+ * arg:   + tOptDesc* + pOptDesc  + the descriptor for this arg +
+ * arg:   + void *    + rng_table + the value range tables      +
+ * arg:   + int       + rng_count + the number of entries       +
+ *
+ * doc:
+ *   Show information about a numeric option with range constraints.
+=*/
+void
+optionShowRange(tOptions* pOpts, tOptDesc* pOD, void * rng_table, int rng_ct)
+{
+    static char const bullet[] = "\t\t\t\t- ";
+    static char const deepin[] = "\t\t\t\t  ";
+    static char const onetab[] = "\t";
+
+    const struct {long const rmin, rmax;} * rng = rng_table;
+
+    char const * pz_indent    = bullet;
+
+    /*
+     * The range is shown only for full usage requests and an error
+     * in this particular option.
+     */
+    if (pOpts != OPTPROC_EMIT_USAGE) {
+        if (pOpts <= OPTPROC_EMIT_LIMIT)
+            return;
+        pz_indent = onetab;
+
+        fprintf(option_usage_fp, zRangeErr, pOpts->pzProgName,
+                pOD->pz_Name, pOD->optArg.argString);
+        pz_indent = "";
+    }
+
+    if (pOD->fOptState & OPTST_SCALED_NUM)
+        fprintf(option_usage_fp, zRangeScaled, pz_indent);
+
+    fprintf(option_usage_fp, (rng_ct > 1) ? zRangeLie : zRangeOnly, pz_indent);
+    pz_indent = (pOpts != OPTPROC_EMIT_USAGE) ? onetab : deepin;
+
+    for (;;) {
+        if (rng->rmax == LONG_MIN)
+            fprintf(option_usage_fp, zRangeExact, pz_indent, rng->rmin);
+        else if (rng->rmin == LONG_MIN)
+            fprintf(option_usage_fp, zRangeUpto, pz_indent, rng->rmax);
+        else if (rng->rmax == LONG_MAX)
+            fprintf(option_usage_fp, zRangeAbove, pz_indent, rng->rmin);
+        else
+            fprintf(option_usage_fp, zRange, pz_indent, rng->rmin,
+                    rng->rmax);
+
+        if  (--rng_ct <= 0) {
+            fputc('\n', option_usage_fp);
+            break;
+        }
+        fputs(zRangeOr, option_usage_fp);
+        rng++;
+    }
+
+    if (pOpts > OPTPROC_EMIT_LIMIT)
+        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+}
+
+/*=export_func  optionNumericVal
+ * private:
+ *
+ * what:  process an option with a numeric value.
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Decipher a numeric value.
+=*/
+void
+optionNumericVal(tOptions* pOpts, tOptDesc* pOD )
+{
+    char* pz;
+    long  val;
+
+    /*
+     *  Numeric options may have a range associated with it.
+     *  If it does, the usage procedure requests that it be
+     *  emitted by passing a NULL pOD pointer.  Also bail out
+     *  if there is no option argument or if we are being reset.
+     */
+    if (  (pOD == NULL)
+       || (pOD->optArg.argString == NULL)
+       || ((pOD->fOptState & OPTST_RESET) != 0))
+        return;
+
+    errno = 0;
+    val = strtol(pOD->optArg.argString, &pz, 0);
+    if ((pz == pOD->optArg.argString) || (errno != 0))
+        goto bad_number;
+
+    if ((pOD->fOptState & OPTST_SCALED_NUM) != 0)
+        switch (*(pz++)) {
+        case '\0': pz--; break;
+        case 't':  val *= 1000;
+        case 'g':  val *= 1000;
+        case 'm':  val *= 1000;
+        case 'k':  val *= 1000; break;
+
+        case 'T':  val *= 1024;
+        case 'G':  val *= 1024;
+        case 'M':  val *= 1024;
+        case 'K':  val *= 1024; break;
+
+        default:   goto bad_number;
+        }
+
+    if (*pz != NUL)
+        goto bad_number;
+
+    if (pOD->fOptState & OPTST_ALLOC_ARG) {
+        AGFREE(pOD->optArg.argString);
+        pOD->fOptState &= ~OPTST_ALLOC_ARG;
+    }
+
+    pOD->optArg.argInt = val;
+    return;
+
+    bad_number:
+
+    fprintf( stderr, zNotNumber, pOpts->pzProgName, pOD->optArg.argString );
+    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
+        (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+
+    errno = EINVAL;
+    pOD->optArg.argInt = ~0;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/numeric.c */
diff --git a/libopts/parse-duration.c b/libopts/parse-duration.c
new file mode 100644 (file)
index 0000000..0a8c4ad
--- /dev/null
@@ -0,0 +1,601 @@
+/* Parse a time duration and return a seconds count
+   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Written by Bruce Korb <bkorb@gnu.org>, 2008.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "parse-duration.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef NUL
+#define NUL '\0'
+#endif
+
+#define cch_t char const
+
+typedef enum {
+  NOTHING_IS_DONE,
+  YEAR_IS_DONE,
+  MONTH_IS_DONE,
+  WEEK_IS_DONE,
+  DAY_IS_DONE,
+  HOUR_IS_DONE,
+  MINUTE_IS_DONE,
+  SECOND_IS_DONE
+} whats_done_t;
+
+#define SEC_PER_MIN     60
+#define SEC_PER_HR      (SEC_PER_MIN * 60)
+#define SEC_PER_DAY     (SEC_PER_HR  * 24)
+#define SEC_PER_WEEK    (SEC_PER_DAY * 7)
+#define SEC_PER_MONTH   (SEC_PER_DAY * 30)
+#define SEC_PER_YEAR    (SEC_PER_DAY * 365)
+
+#define TIME_MAX        0x7FFFFFFF
+
+/* Wrapper around strtoul that does not require a cast.  */
+static unsigned long inline
+str_const_to_ul (cch_t * str, cch_t ** ppz, int base)
+{
+  return strtoul (str, (char **)ppz, base);
+}
+
+/* Wrapper around strtol that does not require a cast.  */
+static long inline
+str_const_to_l (cch_t * str, cch_t ** ppz, int base)
+{
+  return strtol (str, (char **)ppz, base);
+}
+
+/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME
+   with errno set as an error situation, and returning BAD_TIME
+   with errno set in an error situation.  */
+static time_t inline
+scale_n_add (time_t base, time_t val, int scale)
+{
+  if (base == BAD_TIME)
+    {
+      if (errno == 0)
+        errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  if (val > TIME_MAX / scale)
+    {
+      errno = ERANGE;
+      return BAD_TIME;
+    }
+
+  val *= scale;
+  if (base > TIME_MAX - val)
+    {
+      errno = ERANGE;
+      return BAD_TIME;
+    }
+
+  return base + val;
+}
+
+/* After a number HH has been parsed, parse subsequent :MM or :MM:SS.  */
+static time_t
+parse_hr_min_sec (time_t start, cch_t * pz)
+{
+  int lpct = 0;
+
+  errno = 0;
+
+  /* For as long as our scanner pointer points to a colon *AND*
+     we've not looped before, then keep looping.  (two iterations max) */
+  while ((*pz == ':') && (lpct++ <= 1))
+    {
+      unsigned long v = str_const_to_ul (pz+1, &pz, 10);
+
+      if (errno != 0)
+        return BAD_TIME;
+
+      start = scale_n_add (v, start, 60);
+
+      if (errno != 0)
+        return BAD_TIME;
+    }
+
+  /* allow for trailing spaces */
+  while (isspace ((unsigned char)*pz))
+    pz++;
+  if (*pz != NUL)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  return start;
+}
+
+/* Parses a value and returns BASE + value * SCALE, interpreting
+   BASE = BAD_TIME with errno set as an error situation, and returning
+   BAD_TIME with errno set in an error situation.  */
+static time_t
+parse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale)
+{
+  cch_t * pz = *ppz;
+  time_t val;
+
+  if (base == BAD_TIME)
+    return base;
+
+  errno = 0;
+  val = str_const_to_ul (pz, &pz, 10);
+  if (errno != 0)
+    return BAD_TIME;
+  while (isspace ((unsigned char)*pz))
+    pz++;
+  if (pz != endp)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  *ppz = pz;
+  return scale_n_add (base, val, scale);
+}
+
+/* Parses the syntax YEAR-MONTH-DAY.
+   PS points into the string, after "YEAR", before "-MONTH-DAY".  */
+static time_t
+parse_year_month_day (cch_t * pz, cch_t * ps)
+{
+  time_t res = 0;
+
+  res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
+
+  pz++; /* over the first '-' */
+  ps = strchr (pz, '-');
+  if (ps == NULL)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+  res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
+
+  pz++; /* over the second '-' */
+  ps = pz + strlen (pz);
+  return parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
+}
+
+/* Parses the syntax YYYYMMDD.  */
+static time_t
+parse_yearmonthday (cch_t * in_pz)
+{
+  time_t res = 0;
+  char   buf[8];
+  cch_t * pz;
+
+  if (strlen (in_pz) != 8)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  memcpy (buf, in_pz, 4);
+  buf[4] = NUL;
+  pz = buf;
+  res = parse_scaled_value (0, &pz, buf + 4, SEC_PER_YEAR);
+
+  memcpy (buf, in_pz + 4, 2);
+  buf[2] = NUL;
+  pz =   buf;
+  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MONTH);
+
+  memcpy (buf, in_pz + 6, 2);
+  buf[2] = NUL;
+  pz =   buf;
+  return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY);
+}
+
+/* Parses the syntax yy Y mm M ww W dd D.  */
+static time_t
+parse_YMWD (cch_t * pz)
+{
+  time_t res = 0;
+  cch_t * ps = strchr (pz, 'Y');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
+      pz++;
+    }
+
+  ps = strchr (pz, 'M');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
+      pz++;
+    }
+
+  ps = strchr (pz, 'W');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (res, &pz, ps, SEC_PER_WEEK);
+      pz++;
+    }
+
+  ps = strchr (pz, 'D');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
+      pz++;
+    }
+
+  while (isspace ((unsigned char)*pz))
+    pz++;
+  if (*pz != NUL)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  return res;
+}
+
+/* Parses the syntax HH:MM:SS.
+   PS points into the string, after "HH", before ":MM:SS".  */
+static time_t
+parse_hour_minute_second (cch_t * pz, cch_t * ps)
+{
+  time_t res = 0;
+
+  res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
+
+  pz++;
+  ps = strchr (pz, ':');
+  if (ps == NULL)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
+
+  pz++;
+  ps = pz + strlen (pz);
+  return parse_scaled_value (res, &pz, ps, 1);
+}
+
+/* Parses the syntax HHMMSS.  */
+static time_t
+parse_hourminutesecond (cch_t * in_pz)
+{
+  time_t res = 0;
+  char   buf[4];
+  cch_t * pz;
+
+  if (strlen (in_pz) != 6)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  memcpy (buf, in_pz, 2);
+  buf[2] = NUL;
+  pz = buf;
+  res = parse_scaled_value (0, &pz, buf + 2, SEC_PER_HR);
+
+  memcpy (buf, in_pz + 2, 2);
+  buf[2] = NUL;
+  pz =   buf;
+  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MIN);
+
+  memcpy (buf, in_pz + 4, 2);
+  buf[2] = NUL;
+  pz =   buf;
+  return parse_scaled_value (res, &pz, buf + 2, 1);
+}
+
+/* Parses the syntax hh H mm M ss S.  */
+static time_t
+parse_HMS (cch_t * pz)
+{
+  time_t res = 0;
+  cch_t * ps = strchr (pz, 'H');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
+      pz++;
+    }
+
+  ps = strchr (pz, 'M');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
+      pz++;
+    }
+
+  ps = strchr (pz, 'S');
+  if (ps != NULL)
+    {
+      res = parse_scaled_value (res, &pz, ps, 1);
+      pz++;
+    }
+
+  while (isspace ((unsigned char)*pz))
+    pz++;
+  if (*pz != NUL)
+    {
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+
+  return res;
+}
+
+/* Parses a time (hours, minutes, seconds) specification in either syntax.  */
+static time_t
+parse_time (cch_t * pz)
+{
+  cch_t * ps;
+  time_t  res = 0;
+
+  /*
+   *  Scan for a hyphen
+   */
+  ps = strchr (pz, ':');
+  if (ps != NULL)
+    {
+      res = parse_hour_minute_second (pz, ps);
+    }
+
+  /*
+   *  Try for a 'H', 'M' or 'S' suffix
+   */
+  else if (ps = strpbrk (pz, "HMS"),
+           ps == NULL)
+    {
+      /* Its a YYYYMMDD format: */
+      res = parse_hourminutesecond (pz);
+    }
+
+  else
+    res = parse_HMS (pz);
+
+  return res;
+}
+
+/* Returns a substring of the given string, with spaces at the beginning and at
+   the end destructively removed, per SNOBOL.  */
+static char *
+trim (char * pz)
+{
+  /* trim leading white space */
+  while (isspace ((unsigned char)*pz))
+    pz++;
+
+  /* trim trailing white space */
+  {
+    char * pe = pz + strlen (pz);
+    while ((pe > pz) && isspace ((unsigned char)pe[-1]))
+      pe--;
+    *pe = NUL;
+  }
+
+  return pz;
+}
+
+/*
+ *  Parse the year/months/days of a time period
+ */
+static time_t
+parse_period (cch_t * in_pz)
+{
+  char * pT;
+  char * ps;
+  char * pz   = strdup (in_pz);
+  void * fptr = pz;
+  time_t res  = 0;
+
+  if (pz == NULL)
+    {
+      errno = ENOMEM;
+      return BAD_TIME;
+    }
+
+  pT = strchr (pz, 'T');
+  if (pT != NULL)
+    {
+      *(pT++) = NUL;
+      pz = trim (pz);
+      pT = trim (pT);
+    }
+
+  /*
+   *  Scan for a hyphen
+   */
+  ps = strchr (pz, '-');
+  if (ps != NULL)
+    {
+      res = parse_year_month_day (pz, ps);
+    }
+
+  /*
+   *  Try for a 'Y', 'M' or 'D' suffix
+   */
+  else if (ps = strpbrk (pz, "YMWD"),
+           ps == NULL)
+    {
+      /* Its a YYYYMMDD format: */
+      res = parse_yearmonthday (pz);
+    }
+
+  else
+    res = parse_YMWD (pz);
+
+  if ((errno == 0) && (pT != NULL))
+    {
+      time_t val = parse_time (pT);
+      res = scale_n_add (res, val, 1);
+    }
+
+  free (fptr);
+  return res;
+}
+
+static time_t
+parse_non_iso8601 (cch_t * pz)
+{
+  whats_done_t whatd_we_do = NOTHING_IS_DONE;
+
+  time_t res = 0;
+
+  do  {
+    time_t val;
+
+    errno = 0;
+    val = str_const_to_l (pz, &pz, 10);
+    if (errno != 0)
+      goto bad_time;
+
+    /*  IF we find a colon, then we're going to have a seconds value.
+        We will not loop here any more.  We cannot already have parsed
+        a minute value and if we've parsed an hour value, then the result
+        value has to be less than an hour. */
+    if (*pz == ':')
+      {
+        if (whatd_we_do >= MINUTE_IS_DONE)
+          break;
+
+        val = parse_hr_min_sec (val, pz);
+
+        if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR))
+          break;
+
+        return scale_n_add (res, val, 1);
+      }
+
+    {
+      unsigned int mult;
+
+      /*  Skip over white space following the number we just parsed. */
+      while (isspace ((unsigned char)*pz))
+        pz++;
+
+      switch (*pz)
+        {
+        default:  goto bad_time;
+        case NUL:
+          return scale_n_add (res, val, 1);
+
+        case 'y': case 'Y':
+          if (whatd_we_do >= YEAR_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_YEAR;
+          whatd_we_do = YEAR_IS_DONE;
+          break;
+
+        case 'M':
+          if (whatd_we_do >= MONTH_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_MONTH;
+          whatd_we_do = MONTH_IS_DONE;
+          break;
+
+        case 'W':
+          if (whatd_we_do >= WEEK_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_WEEK;
+          whatd_we_do = WEEK_IS_DONE;
+          break;
+
+        case 'd': case 'D':
+          if (whatd_we_do >= DAY_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_DAY;
+          whatd_we_do = DAY_IS_DONE;
+          break;
+
+        case 'h':
+          if (whatd_we_do >= HOUR_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_HR;
+          whatd_we_do = HOUR_IS_DONE;
+          break;
+
+        case 'm':
+          if (whatd_we_do >= MINUTE_IS_DONE)
+            goto bad_time;
+          mult = SEC_PER_MIN;
+          whatd_we_do = MINUTE_IS_DONE;
+          break;
+
+        case 's':
+          mult = 1;
+          whatd_we_do = SECOND_IS_DONE;
+          break;
+        }
+
+      res = scale_n_add (res, val, mult);
+
+      pz++;
+      while (isspace ((unsigned char)*pz))
+        pz++;
+      if (*pz == NUL)
+        return res;
+
+      if (! isdigit ((unsigned char)*pz))
+        break;
+    }
+
+  } while (whatd_we_do < SECOND_IS_DONE);
+
+ bad_time:
+  errno = EINVAL;
+  return BAD_TIME;
+}
+
+time_t
+parse_duration (char const * pz)
+{
+  while (isspace ((unsigned char)*pz))
+    pz++;
+
+  switch (*pz)
+    {
+    case 'P':
+      return parse_period (pz + 1);
+
+    case 'T':
+      return parse_time (pz + 1);
+
+    default:
+      if (isdigit ((unsigned char)*pz))
+        return parse_non_iso8601 (pz);
+
+      errno = EINVAL;
+      return BAD_TIME;
+    }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of parse-duration.c */
diff --git a/libopts/parse-duration.h b/libopts/parse-duration.h
new file mode 100644 (file)
index 0000000..9fd2a36
--- /dev/null
@@ -0,0 +1,90 @@
+/* Parse a time duration and return a seconds count
+   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Written by Bruce Korb <bkorb@gnu.org>, 2008.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+
+  Readers and users of this function are referred to the ISO-8601
+  specification, with particular attention to "Durations".
+
+  At the time of writing, this worked:
+
+  http://en.wikipedia.org/wiki/ISO_8601#Durations
+
+  The string must start with a 'P', 'T' or a digit.
+
+  ==== if it is a digit
+
+  the string may contain:  NNN Y NNN M NNN W NNN d NNN h NNN m NNN s
+  This represents NNN years, NNN months, NNN weeks, NNN days, NNN hours,
+    NNN minutes and NNN seconds.
+  The embeded white space is optional.
+  These terms must appear in this order.
+  Case is significant:  'M' is months and 'm' is minutes.
+  The final "s" is optional.
+  All of the terms ("NNN" plus designator) are optional.
+  Minutes and seconds may optionally be represented as NNN:NNN.
+  Also, hours, minute and seconds may be represented as NNN:NNN:NNN.
+  There is no limitation on the value of any of the terms, except
+  that the final result must fit in a time_t value.
+
+  ==== if it is a 'P' or 'T', please see ISO-8601 for a rigorous definition.
+
+  The 'P' term may be followed by any of three formats:
+    yyyymmdd
+    yy-mm-dd
+    yy Y mm M ww W dd D
+
+  or it may be empty and followed by a 'T'.  The "yyyymmdd" must be eight
+  digits long.
+
+  NOTE!  Months are always 30 days and years are always 365 days long.
+  5 years is always 1825 days, not 1826 or 1827 depending on leap year
+  considerations.  3 months is always 90 days.  There is no consideration
+  for how many days are in the current, next or previous months.
+
+  For the final format:
+  *  Embedded white space is allowed, but it is optional.
+  *  All of the terms are optional.  Any or all-but-one may be omitted.
+  *  The meanings are yy years, mm months, ww weeks and dd days.
+  *  The terms must appear in this order.
+
+  ==== The 'T' term may be followed by any of these formats:
+
+    hhmmss
+    hh:mm:ss
+    hh H mm M ss S
+
+  For the final format:
+  *  Embedded white space is allowed, but it is optional.
+  *  All of the terms are optional.  Any or all-but-one may be omitted.
+  *  The terms must appear in this order.
+
+ */
+#ifndef GNULIB_PARSE_DURATION_H
+#define GNULIB_PARSE_DURATION_H
+
+#include <time.h>
+
+/* Return value when a valid duration cannot be parsed.  */
+#define BAD_TIME        ((time_t)~0)
+
+/* Parses the given string.  If it has the syntax of a valid duration,
+   this duration is returned.  Otherwise, the return value is BAD_TIME,
+   and errno is set to either EINVAL (bad syntax) or ERANGE (out of range).  */
+extern time_t parse_duration (char const * in_pz);
+
+#endif /* GNULIB_PARSE_DURATION_H */
diff --git a/libopts/pgusage.c b/libopts/pgusage.c
new file mode 100644 (file)
index 0000000..2e21948
--- /dev/null
@@ -0,0 +1,140 @@
+
+/**
+ * \file pgusage.c
+ *
+ * Time-stamp:      "2011-03-25 17:54:41 bkorb"
+ *
+ *   Automated Options Paged Usage module.
+ *
+ *  This routine will run run-on options through a pager so the
+ *  user may examine, print or edit them at their leisure.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*=export_func  optionPagedUsage
+ * private:
+ *
+ * what:  Decipher a boolean value
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Run the usage output through a pager.
+ *  This is very handy if it is very long.
+ *  This is disabled on platforms without a working fork() function.
+=*/
+void
+optionPagedUsage(tOptions* pOptions, tOptDesc* pOD)
+{
+#if ! defined(HAVE_WORKING_FORK)
+    if ((pOD->fOptState & OPTST_RESET) != 0)
+        return;
+
+    (*pOptions->pUsageProc)(pOptions, EXIT_SUCCESS);
+#else
+    static pid_t     my_pid;
+    char zPageUsage[ 1024 ];
+
+    /*
+     *  IF we are being called after the usage proc is done
+     *     (and thus has called "exit(2)")
+     *  THEN invoke the pager to page through the usage file we created.
+     */
+    switch (pagerState) {
+    case PAGER_STATE_INITIAL:
+    {
+        if ((pOD->fOptState & OPTST_RESET) != 0)
+            return;
+
+        my_pid  = getpid();
+#ifdef HAVE_SNPRINTF
+        snprintf(zPageUsage, sizeof(zPageUsage), "/tmp/use.%lu", (tAoUL)my_pid);
+#else
+        sprintf(zPageUsage, "/tmp/use.%lu", (tAoUL)my_pid);
+#endif
+        unlink(zPageUsage);
+
+        /*
+         *  Set usage output to this temporary file
+         */
+        option_usage_fp = fopen(zPageUsage, "w" FOPEN_BINARY_FLAG);
+        if (option_usage_fp == NULL)
+            _exit(EXIT_FAILURE);
+
+        pagerState = PAGER_STATE_READY;
+
+        /*
+         *  Set up so this routine gets called during the exit logic
+         */
+        atexit((void(*)(void))optionPagedUsage);
+
+        /*
+         *  The usage procedure will now put the usage information into
+         *  the temporary file we created above.
+         */
+        (*pOptions->pUsageProc)(pOptions, EXIT_SUCCESS);
+
+        /* NOTREACHED */
+        _exit(EXIT_FAILURE);
+    }
+
+    case PAGER_STATE_READY:
+    {
+        tSCC zPage[]  = "%1$s /tmp/use.%2$lu ; rm -f /tmp/use.%2$lu";
+        tCC* pzPager  = (tCC*)getenv("PAGER");
+
+        /*
+         *  Use the "more(1)" program if "PAGER" has not been defined
+         */
+        if (pzPager == NULL)
+            pzPager = "more";
+
+        /*
+         *  Page the file and remove it when done.
+         */
+#ifdef HAVE_SNPRINTF
+        snprintf(zPageUsage, sizeof(zPageUsage), zPage, pzPager, (tAoUL)my_pid);
+#else
+        sprintf(zPageUsage, zPage, pzPager, (tAoUL)my_pid);
+#endif
+        fclose(stderr);
+        dup2(STDOUT_FILENO, STDERR_FILENO);
+
+        (void)system(zPageUsage);
+    }
+
+    case PAGER_STATE_CHILD:
+        /*
+         *  This is a child process used in creating shell script usage.
+         */
+        break;
+    }
+#endif
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/pgusage.c */
diff --git a/libopts/proto.h b/libopts/proto.h
new file mode 100644 (file)
index 0000000..48746f1
--- /dev/null
@@ -0,0 +1,133 @@
+/* -*- buffer-read-only: t -*- vi: set ro:
+ *
+ * Prototypes for autoopts
+ * Generated Thu Dec 29 12:02:41 PST 2011
+ */
+#ifndef AUTOOPTS_PROTO_H_GUARD
+#define AUTOOPTS_PROTO_H_GUARD 1
+
+#ifndef LOCAL
+#  define LOCAL extern
+#  define REDEF_LOCAL 1
+#else
+#  undef  REDEF_LOCAL
+#endif
+/*
+ *  Extracted from autoopts.c
+ */
+LOCAL void *
+ao_malloc(size_t sz);
+
+LOCAL void *
+ao_realloc(void *p, size_t sz);
+
+LOCAL char *
+ao_strdup(char const *str);
+
+LOCAL tSuccess
+handle_opt(tOptions * pOpts, tOptState* pOptState);
+
+LOCAL tSuccess
+immediate_opts(tOptions * pOpts);
+
+LOCAL tSuccess
+regular_opts(tOptions * pOpts);
+
+/*
+ *  Extracted from check.c
+ */
+LOCAL ag_bool
+is_consistent(tOptions * pOpts);
+
+/*
+ *  Extracted from configfile.c
+ */
+LOCAL void
+intern_file_load(tOptions* pOpts);
+
+LOCAL char*
+parseAttributes(
+    tOptions*           pOpts,
+    char*               pzText,
+    tOptionLoadMode*    pMode,
+    tOptionValue*       pType );
+
+LOCAL tSuccess
+validate_struct(tOptions * pOpts, char const * pzProgram);
+
+/*
+ *  Extracted from env.c
+ */
+LOCAL void
+doPrognameEnv(tOptions * pOpts, teEnvPresetType type);
+
+LOCAL void
+env_presets(tOptions * pOpts, teEnvPresetType type);
+
+/*
+ *  Extracted from find.c
+ */
+LOCAL tSuccess
+opt_find_long(tOptions * pOpts, char const * opt_name, tOptState * pOptState);
+
+LOCAL tSuccess
+opt_find_short(tOptions* pOpts, uint_t optValue, tOptState* pOptState);
+
+LOCAL tSuccess
+get_opt_arg(tOptions * pOpts, tOptState * pOptState);
+
+LOCAL tSuccess
+find_opt(tOptions * pOpts, tOptState * pOptState);
+
+/*
+ *  Extracted from load.c
+ */
+LOCAL void
+mungeString(char* pzTxt, tOptionLoadMode mode);
+
+LOCAL void
+loadOptionLine(
+    tOptions*   pOpts,
+    tOptState*  pOS,
+    char*       pzLine,
+    tDirection  direction,
+    tOptionLoadMode   load_mode );
+
+/*
+ *  Extracted from nested.c
+ */
+LOCAL void
+unload_arg_list(tArgList* pAL);
+
+LOCAL tOptionValue*
+optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen);
+
+LOCAL int
+get_special_char(char const ** ppz, int * ct);
+
+LOCAL void
+emit_special_char(FILE * fp, int ch);
+
+/*
+ *  Extracted from sort.c
+ */
+LOCAL void
+optionSort(tOptions* pOpts);
+
+/*
+ *  Extracted from stack.c
+ */
+LOCAL void
+addArgListEntry(void** ppAL, void* entry);
+
+/*
+ *  Extracted from usage.c
+ */
+LOCAL void
+set_usage_flags(tOptions * opts, char const * flg_txt);
+
+#ifdef REDEF_LOCAL
+#  undef LOCAL
+#  define LOCAL
+#endif
+#endif /* AUTOOPTS_PROTO_H_GUARD */
diff --git a/libopts/putshell.c b/libopts/putshell.c
new file mode 100644 (file)
index 0000000..f15284f
--- /dev/null
@@ -0,0 +1,372 @@
+
+/**
+ * \file putshell.c
+ *
+ * Time-stamp:      "2010-09-05 06:10:56 bkorb"
+ *
+ *  This module will interpret the options set in the tOptions
+ *  structure and print them to standard out in a fashion that
+ *  will allow them to be interpreted by the Bourne or Korn shells.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+static char const zOptValFmt[] = "%s_%s=";
+static char const zOptEnd[]    = "\nexport %s_%s\n";
+static char const zOptNumFmt[] = "%1$s_%2$s=%3$d # 0x%3$X\nexport %1$s_%2$s\n";
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+print_quot_str(tCC* pzStr);
+
+static void
+print_enumeration(tOptions * pOpts, tOptDesc * pOD);
+
+static void
+print_membership(tOptions * pOpts, tOptDesc * pOD);
+
+static void
+print_stacked_arg(tOptions * pOpts, tOptDesc * pOD);
+
+static void
+print_reordering(tOptions * pOpts);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*
+ *  Make sure embedded single quotes come out okay.  The initial quote has
+ *  been emitted and the closing quote will be upon return.
+ */
+static void
+print_quot_str(tCC* pzStr)
+{
+    /*
+     *  Handle empty strings to make the rest of the logic simpler.
+     */
+    if ((pzStr == NULL) || (*pzStr == NUL)) {
+        fputs("''", stdout);
+        return;
+    }
+
+    /*
+     *  Emit any single quotes/apostrophes at the start of the string and
+     *  bail if that is all we need to do.
+     */
+    while (*pzStr == '\'') {
+        fputs("\\'", stdout);
+        pzStr++;
+    }
+    if (*pzStr == NUL)
+        return;
+
+    /*
+     *  Start the single quote string
+     */
+    fputc('\'', stdout);
+    for (;;) {
+        tCC* pz = strchr(pzStr, '\'');
+        if (pz == NULL)
+            break;
+
+        /*
+         *  Emit the string up to the single quote (apostrophe) we just found.
+         */
+        (void)fwrite(pzStr, (size_t)(pz - pzStr), (size_t)1, stdout);
+        fputc('\'', stdout);
+        pzStr = pz;
+
+        /*
+         *  Emit an escaped apostrophe for every one we find.
+         *  If that ends the string, do not re-open the single quotes.
+         */
+        while (*++pzStr == '\'')   fputs("\\'", stdout);
+        if (*pzStr == NUL)
+            return;
+
+        fputc('\'', stdout);
+    }
+
+    /*
+     *  If we broke out of the loop, we must still emit the remaining text
+     *  and then close the single quote string.
+     */
+    fputs(pzStr, stdout);
+    fputc('\'', stdout);
+}
+
+static void
+print_enumeration(tOptions * pOpts, tOptDesc * pOD)
+{
+    uintptr_t e_val = pOD->optArg.argEnum;
+    printf(zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME);
+
+    /*
+     *  Convert value to string, print that and restore numeric value.
+     */
+    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
+    printf("'%s'", pOD->optArg.argString);
+    if (pOD->fOptState & OPTST_ALLOC_ARG)
+        AGFREE(pOD->optArg.argString);
+    pOD->optArg.argEnum = e_val;
+
+    printf(zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME);
+}
+
+static void
+print_membership(tOptions * pOpts, tOptDesc * pOD)
+{
+    char const * pz;
+    uintptr_t val = 1;
+    printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
+           (int)(uintptr_t)(pOD->optCookie));
+    pOD->optCookie = (void*)(uintptr_t)~0UL;
+    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
+
+    /*
+     *  We are building the typeset list.  The list returned starts with
+     *  'none + ' for use by option saving stuff.  We must ignore that.
+     */
+    pz = pOD->optArg.argString + 7;
+    while (*pz != NUL) {
+        printf("typeset -x -i %s_", pOD->pz_NAME);
+        while (IS_PLUS_N_SPACE_CHAR(*pz))  pz++;
+
+        for (;;) {
+            int ch = *(pz++);
+            if (IS_LOWER_CASE_CHAR(ch))   fputc(toupper(ch), stdout);
+            else if (IS_UPPER_CASE_CHAR(ch))   fputc(ch, stdout);
+            else if (IS_PLUS_N_SPACE_CHAR(ch)) goto name_done;
+            else if (ch == NUL)        { pz--; goto name_done; }
+            else fputc('_', stdout);
+        } name_done:;
+        printf("=%1$lu # 0x%1$lX\n", (unsigned long)val);
+        val <<= 1;
+    }
+
+    AGFREE(pOD->optArg.argString);
+    pOD->optArg.argString = NULL;
+    pOD->fOptState &= ~OPTST_ALLOC_ARG;
+}
+
+static void
+print_stacked_arg(tOptions * pOpts, tOptDesc * pOD)
+{
+    tSCC zOptCookieCt[] = "%1$s_%2$s_CT=%3$d\nexport %1$s_%2$s_CT\n";
+
+    tArgList*    pAL = (tArgList*)pOD->optCookie;
+    tCC**        ppz = pAL->apzArgs;
+    int          ct  = pAL->useCt;
+
+    printf(zOptCookieCt, pOpts->pzPROGNAME, pOD->pz_NAME, ct);
+
+    while (--ct >= 0) {
+        tSCC numarg_z[] = "%s_%s_%d=";
+        tSCC end_z[]    = "\nexport %s_%s_%d\n";
+
+        printf(numarg_z, pOpts->pzPROGNAME, pOD->pz_NAME,
+               pAL->useCt - ct);
+        print_quot_str(*(ppz++));
+        printf(end_z, pOpts->pzPROGNAME, pOD->pz_NAME,
+               pAL->useCt - ct);
+    }
+}
+
+static void
+print_reordering(tOptions * pOpts)
+{
+    int  optIx;
+
+    fputs("set --", stdout);
+
+    for (optIx = pOpts->curOptIdx; optIx < pOpts->origArgCt; optIx++) {
+
+        char* pzArg = pOpts->origArgVect[ optIx ];
+
+        if (strchr(pzArg, '\'') == NULL)
+            printf(" '%s'", pzArg);
+
+        else {
+            fputs(" '", stdout);
+            for (;;) {
+                char ch = *(pzArg++);
+                switch (ch) {
+                case '\'':  fputs("'\\''", stdout); break;
+                case NUL:   goto arg_done;
+                default:    fputc(ch, stdout); break;
+                }
+            } arg_done:;
+            fputc('\'', stdout);
+        }
+    }
+    fputs("\nOPTION_CT=0\n", stdout);
+}
+
+/*=export_func  optionPutShell
+ * what:  write a portable shell script to parse options
+ * private:
+ * arg:   tOptions*, pOpts, the program options descriptor
+ * doc:   This routine will emit portable shell script text for parsing
+ *        the options described in the option definitions.
+=*/
+void
+optionPutShell(tOptions* pOpts)
+{
+    int  optIx = 0;
+    tSCC zOptCtFmt[]  = "OPTION_CT=%d\nexport OPTION_CT\n";
+    tSCC zOptDisabl[] = "%1$s_%2$s=%3$s\nexport %1$s_%2$s\n";
+    tSCC zFullOptFmt[]= "%1$s_%2$s='%3$s'\nexport %1$s_%2$s\n";
+    tSCC zEquivMode[] = "%1$s_%2$s_MODE='%3$s'\nexport %1$s_%2$s_MODE\n";
+
+    printf(zOptCtFmt, pOpts->curOptIdx-1);
+
+    do  {
+        tOptDesc* pOD = pOpts->pOptDesc + optIx;
+
+        if (SKIP_OPT(pOD))
+            continue;
+
+        /*
+         *  Equivalence classes are hard to deal with.  Where the
+         *  option data wind up kind of squishes around.  For the purposes
+         *  of emitting shell state, they are not recommended, but we'll
+         *  do something.  I guess we'll emit the equivalenced-to option
+         *  at the point in time when the base option is found.
+         */
+        if (pOD->optEquivIndex != NO_EQUIVALENT)
+            continue; /* equivalence to a different option */
+
+        /*
+         *  Equivalenced to a different option.  Process the current option
+         *  as the equivalenced-to option.  Keep the persistent state bits,
+         *  but copy over the set-state bits.
+         */
+        if (pOD->optActualIndex != optIx) {
+            tOptDesc* p   = pOpts->pOptDesc + pOD->optActualIndex;
+            p->optArg     = pOD->optArg;
+            p->fOptState &= OPTST_PERSISTENT_MASK;
+            p->fOptState |= pOD->fOptState & ~OPTST_PERSISTENT_MASK;
+            printf(zEquivMode, pOpts->pzPROGNAME, pOD->pz_NAME, p->pz_NAME);
+            pOD = p;
+        }
+
+        /*
+         *  If the argument type is a set membership bitmask, then we always
+         *  emit the thing.  We do this because it will always have some sort
+         *  of bitmask value and we need to emit the bit values.
+         */
+        if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
+            print_membership(pOpts, pOD);
+            continue;
+        }
+
+        /*
+         *  IF the option was either specified or it wakes up enabled,
+         *  then we will emit information.  Otherwise, skip it.
+         *  The idea is that if someone defines an option to initialize
+         *  enabled, we should tell our shell script that it is enabled.
+         */
+        if (UNUSED_OPT(pOD) && DISABLED_OPT(pOD)) {
+            continue;
+        }
+
+        /*
+         *  Handle stacked arguments
+         */
+        if (  (pOD->fOptState & OPTST_STACKED)
+           && (pOD->optCookie != NULL) )  {
+            print_stacked_arg(pOpts, pOD);
+            continue;
+        }
+
+        /*
+         *  If the argument has been disabled,
+         *  Then set its value to the disablement string
+         */
+        if ((pOD->fOptState & OPTST_DISABLED) != 0) {
+            printf(zOptDisabl, pOpts->pzPROGNAME, pOD->pz_NAME,
+                   (pOD->pz_DisablePfx != NULL)
+                   ? pOD->pz_DisablePfx : "false");
+            continue;
+        }
+
+        /*
+         *  If the argument type is numeric, the last arg pointer
+         *  is really the VALUE of the string that was pointed to.
+         */
+        if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) {
+            printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
+                   (int)pOD->optArg.argInt);
+            continue;
+        }
+
+        /*
+         *  If the argument type is an enumeration, then it is much
+         *  like a text value, except we call the callback function
+         *  to emit the value corresponding to the "optArg" number.
+         */
+        if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_ENUMERATION) {
+            print_enumeration(pOpts, pOD);
+            continue;
+        }
+
+        /*
+         *  If the argument type is numeric, the last arg pointer
+         *  is really the VALUE of the string that was pointed to.
+         */
+        if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_BOOLEAN) {
+            printf(zFullOptFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
+                   (pOD->optArg.argBool == 0) ? "false" : "true");
+            continue;
+        }
+
+        /*
+         *  IF the option has an empty value,
+         *  THEN we set the argument to the occurrence count.
+         */
+        if (  (pOD->optArg.argString == NULL)
+           || (pOD->optArg.argString[0] == NUL) ) {
+
+            printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
+                   pOD->optOccCt);
+            continue;
+        }
+
+        /*
+         *  This option has a text value
+         */
+        printf(zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME);
+        print_quot_str(pOD->optArg.argString);
+        printf(zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME);
+
+    } while (++optIx < pOpts->presetOptCt );
+
+    if (  ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
+       && (pOpts->curOptIdx < pOpts->origArgCt))
+        print_reordering(pOpts);
+
+    fflush(stdout);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/putshell.c */
diff --git a/libopts/reset.c b/libopts/reset.c
new file mode 100644 (file)
index 0000000..59850fe
--- /dev/null
@@ -0,0 +1,135 @@
+
+/**
+ * \file reset.c
+ *
+ *  Time-stamp:      "2011-05-24 18:07:16 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+static void
+optionReset( tOptions* pOpts, tOptDesc* pOD )
+{
+    pOD->fOptState &= OPTST_PERSISTENT_MASK;
+    pOD->fOptState |= OPTST_RESET;
+    if (pOD->pOptProc != NULL)
+        pOD->pOptProc(pOpts, pOD);
+    pOD->optArg.argString =
+        pOpts->originalOptArgArray[ pOD->optIndex ].argString;
+    pOD->optCookie = pOpts->originalOptArgCookie[ pOD->optIndex ];
+    pOD->fOptState &= OPTST_PERSISTENT_MASK;
+}
+
+
+static void
+optionResetEverything(tOptions * pOpts)
+{
+    tOptDesc * pOD = pOpts->pOptDesc;
+    int        ct  = pOpts->presetOptCt;
+
+    for (;;) {
+        optionReset(pOpts, pOD);
+
+        if (--ct <= 0)
+            break;
+        pOD++;
+    }
+}
+
+
+/*=export_func  optionResetOpt
+ * private:
+ *
+ * what:  Reset the value of an option
+ * arg:   + tOptions* + pOpts    + program options descriptor  +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  This code will cause another option to be reset to its initial state.
+ *  For example, --reset=foo will cause the --foo option to be reset.
+=*/
+void
+optionResetOpt( tOptions* pOpts, tOptDesc* pOD )
+{
+    static ag_bool reset_active = AG_FALSE;
+
+    tOptState opt_state = OPTSTATE_INITIALIZER(DEFINED);
+    char const * pzArg = pOD->optArg.argString;
+    tSuccess     succ;
+
+    if (reset_active)
+        return;
+
+    if (  (! HAS_originalOptArgArray(pOpts))
+       || (pOpts->originalOptArgCookie == NULL)) {
+        fputs(zResetNotConfig, stderr);
+        _exit(EX_SOFTWARE);
+    }
+
+    if ((pzArg == NULL) || (*pzArg == NUL)) {
+        fputs(zNoResetArg, stderr);
+        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+        /* NOTREACHED */
+        assert(0 == 1);
+    }
+
+    reset_active = AG_TRUE;
+
+    if (pzArg[1] == NUL) {
+        if (*pzArg == '*') {
+            optionResetEverything(pOpts);
+            reset_active = AG_FALSE;
+            return;
+        }
+
+        succ = opt_find_short(pOpts, (tAoUC)*pzArg, &opt_state);
+        if (! SUCCESSFUL(succ)) {
+            fprintf(stderr, zIllOptChr, pOpts->pzProgPath, *pzArg);
+            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+            assert(0 == 1);
+        }
+    } else {
+        succ = opt_find_long(pOpts, (char *)pzArg, &opt_state);
+        if (! SUCCESSFUL(succ)) {
+            fprintf(stderr, zIllOptStr, pOpts->pzProgPath, pzArg);
+            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
+            /* NOTREACHED */
+            assert(0 == 1);
+        }
+    }
+
+    /*
+     *  We've found the indicated option.  Turn off all non-persistent
+     *  flags because we're forcing the option back to its initialized state.
+     *  Call any callout procedure to handle whatever it needs to.
+     *  Finally, clear the reset flag, too.
+     */
+    optionReset(pOpts, opt_state.pOD);
+    reset_active = AG_FALSE;
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/reset.c */
diff --git a/libopts/restore.c b/libopts/restore.c
new file mode 100644 (file)
index 0000000..f55f3d2
--- /dev/null
@@ -0,0 +1,228 @@
+
+/*
+ * \file restore.c
+ *
+ * Time-stamp:      "2010-08-22 11:04:00 bkorb"
+ *
+ *  This module's routines will save the current option state to memory
+ *  and restore it.  If saved prior to the initial optionProcess call,
+ *  then the initial state will be restored.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*
+ *  optionFixupSavedOpts  Really, it just wipes out option state for
+ *  options that are troublesome to copy.  viz., stacked strings and
+ *  hierarcicaly valued option args.  We do duplicate string args that
+ *  have been marked as allocated though.
+ */
+static void
+fixupSavedOptionArgs(tOptions* pOpts)
+{
+    tOptions* p   = pOpts->pSavedState;
+    tOptDesc* pOD = pOpts->pOptDesc;
+    int       ct  = pOpts->optCt;
+
+    /*
+     *  Make sure that allocated stuff is only referenced in the
+     *  archived copy of the data.
+     */
+    for (; ct-- > 0; pOD++)  {
+        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_STRING:
+            if (pOD->fOptState & OPTST_STACKED) {
+                tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
+                q->optCookie = NULL;
+            }
+            if (pOD->fOptState & OPTST_ALLOC_ARG) {
+                tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
+                AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg");
+            }
+            break;
+
+        case OPARG_TYPE_HIERARCHY:
+        {
+            tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
+            q->optCookie = NULL;
+        }
+        }
+    }
+}
+
+/*=export_func optionSaveState
+ *
+ * what:  saves the option state to memory
+ * arg:   tOptions*, pOpts, program options descriptor
+ *
+ * doc:
+ *
+ *  This routine will allocate enough memory to save the current option
+ *  processing state.  If this routine has been called before, that memory
+ *  will be reused.  You may only save one copy of the option state.  This
+ *  routine may be called before optionProcess(3AO).  If you do call it
+ *  before the first call to optionProcess, then you may also change the
+ *  contents of argc/argv after you call optionRestore(3AO)
+ *
+ *  In fact, more strongly put: it is safest to only use this function
+ *  before having processed any options.  In particular, the saving and
+ *  restoring of stacked string arguments and hierarchical values is
+ *  disabled.  The values are not saved.
+ *
+ * err:   If it fails to allocate the memory,
+ *        it will print a message to stderr and exit.
+ *        Otherwise, it will always succeed.
+=*/
+void
+optionSaveState(tOptions* pOpts)
+{
+    tOptions* p = (tOptions*)pOpts->pSavedState;
+
+    if (p == NULL) {
+        size_t sz = sizeof(*pOpts) + (pOpts->optCt * sizeof(tOptDesc));
+        p = AGALOC(sz, "saved option state");
+        if (p == NULL) {
+            tCC* pzName = pOpts->pzProgName;
+            if (pzName == NULL) {
+                pzName = pOpts->pzPROGNAME;
+                if (pzName == NULL)
+                    pzName = zNil;
+            }
+            fprintf(stderr, zCantSave, pzName, sz);
+            exit(EXIT_FAILURE);
+        }
+
+        pOpts->pSavedState = p;
+    }
+
+    memcpy(p, pOpts, sizeof(*p));
+    memcpy(p + 1, pOpts->pOptDesc, p->optCt * sizeof(tOptDesc));
+
+    fixupSavedOptionArgs(pOpts);
+}
+
+
+/*=export_func optionRestore
+ *
+ * what:  restore option state from memory copy
+ * arg:   tOptions*, pOpts, program options descriptor
+ *
+ * doc:  Copy back the option state from saved memory.
+ *       The allocated memory is left intact, so this routine can be
+ *       called repeatedly without having to call optionSaveState again.
+ *       If you are restoring a state that was saved before the first call
+ *       to optionProcess(3AO), then you may change the contents of the
+ *       argc/argv parameters to optionProcess.
+ *
+ * err:  If you have not called @code{optionSaveState} before, a diagnostic is
+ *       printed to @code{stderr} and exit is called.
+=*/
+void
+optionRestore(tOptions* pOpts)
+{
+    tOptions* p = (tOptions*)pOpts->pSavedState;
+
+    if (p == NULL) {
+        tCC* pzName = pOpts->pzProgName;
+        if (pzName == NULL) {
+            pzName = pOpts->pzPROGNAME;
+            if (pzName == NULL)
+                pzName = zNil;
+        }
+        fprintf(stderr, zNoState, pzName);
+        exit(EXIT_FAILURE);
+    }
+
+    pOpts->pSavedState = NULL;
+    optionFree(pOpts);
+
+    memcpy(pOpts, p, sizeof(*p));
+    memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc));
+    pOpts->pSavedState = p;
+
+    fixupSavedOptionArgs(pOpts);
+}
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+/*=export_func optionFree
+ *
+ * what:  free allocated option processing memory
+ * arg:   tOptions*, pOpts, program options descriptor
+ *
+ * doc:   AutoOpts sometimes allocates memory and puts pointers to it in the
+ *        option state structures.  This routine deallocates all such memory.
+ *
+ * err:   As long as memory has not been corrupted,
+ *        this routine is always successful.
+=*/
+void
+optionFree(tOptions* pOpts)
+{
+ free_saved_state:
+    {
+        tOptDesc* p = pOpts->pOptDesc;
+        int ct = pOpts->optCt;
+        do  {
+            if (p->fOptState & OPTST_ALLOC_ARG) {
+                AGFREE(p->optArg.argString);
+                p->optArg.argString = NULL;
+                p->fOptState &= ~OPTST_ALLOC_ARG;
+            }
+
+            switch (OPTST_GET_ARGTYPE(p->fOptState)) {
+            case OPARG_TYPE_STRING:
+#ifdef WITH_LIBREGEX
+                if (  (p->fOptState & OPTST_STACKED)
+                   && (p->optCookie != NULL)) {
+                    p->optArg.argString = ".*";
+                    optionUnstackArg(pOpts, p);
+                }
+#else
+                /* leak memory */;
+#endif
+                break;
+
+            case OPARG_TYPE_HIERARCHY:
+                if (p->optCookie != NULL)
+                    unload_arg_list(p->optCookie);
+                break;
+            }
+
+            p->optCookie = NULL;
+        } while (p++, --ct > 0);
+    }
+    if (pOpts->pSavedState != NULL) {
+        tOptions * p = (tOptions*)pOpts->pSavedState;
+        memcpy(pOpts, p, sizeof(*p));
+        memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc));
+        AGFREE(pOpts->pSavedState);
+        pOpts->pSavedState = NULL;
+        goto free_saved_state;
+    }
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/restore.c */
diff --git a/libopts/save.c b/libopts/save.c
new file mode 100644 (file)
index 0000000..9c36bc8
--- /dev/null
@@ -0,0 +1,784 @@
+
+/*
+ * \file save.c
+ *
+ * Time-stamp:      "2011-04-06 09:21:44 bkorb"
+ *
+ *  This module's routines will take the currently set options and
+ *  store them into an ".rc" file for re-interpretation the next
+ *  time the invoking program is run.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+static char const  zWarn[] = "%s WARNING:  cannot save options - ";
+static char const close_xml[] = "</%s>\n";
+
+/* = = = START-STATIC-FORWARD = = = */
+static tCC*
+findDirName(tOptions* pOpts, int* p_free);
+
+static char const *
+findFileName(tOptions * pOpts, int * p_free_name);
+
+static void
+printEntry(
+    FILE *     fp,
+    tOptDesc * p,
+    tCC*       pzLA );
+
+static void
+print_a_value(FILE * fp, int depth, tOptDesc * pOD, tOptionValue const * ovp);
+
+static void
+print_a_string(FILE * fp, char const * name, char const * pz);
+
+static void
+printValueList(FILE * fp, char const * name, tArgList * al);
+
+static void
+printHierarchy(FILE * fp, tOptDesc * p);
+
+static FILE *
+openSaveFile(tOptions* pOpts);
+
+static void
+printNoArgOpt(FILE * fp, tOptDesc * p, tOptDesc * pOD);
+
+static void
+printStringArg(FILE * fp, tOptDesc * pOD);
+
+static void
+printEnumArg(FILE * fp, tOptDesc * pOD);
+
+static void
+printSetMemberArg(FILE * fp, tOptDesc * pOD);
+
+static void
+printFileArg(FILE * fp, tOptDesc * pOD, tOptions* pOpts);
+/* = = = END-STATIC-FORWARD = = = */
+
+static tCC*
+findDirName(tOptions* pOpts, int* p_free)
+{
+    tCC*  pzDir;
+
+    if (  (pOpts->specOptIdx.save_opts == NO_EQUIVALENT)
+       || (pOpts->specOptIdx.save_opts == 0))
+        return NULL;
+
+    pzDir = pOpts->pOptDesc[ pOpts->specOptIdx.save_opts ].optArg.argString;
+    if ((pzDir != NULL) && (*pzDir != NUL))
+        return pzDir;
+
+    /*
+     *  This function only works if there is a directory where
+     *  we can stash the RC (INI) file.
+     */
+    {
+        tCC* const* papz = pOpts->papzHomeList;
+        if (papz == NULL)
+            return NULL;
+
+        while (papz[1] != NULL) papz++;
+        pzDir = *papz;
+    }
+
+    /*
+     *  IF it does not require deciphering an env value, then just copy it
+     */
+    if (*pzDir != '$')
+        return pzDir;
+
+    {
+        tCC*  pzEndDir = strchr(++pzDir, DIRCH);
+        char* pzFileName;
+        char* pzEnv;
+
+        if (pzEndDir != NULL) {
+            char z[ AO_NAME_SIZE ];
+            if ((pzEndDir - pzDir) > AO_NAME_LIMIT )
+                return NULL;
+            memcpy(z, pzDir, (size_t)(pzEndDir - pzDir));
+            z[pzEndDir - pzDir] = NUL;
+            pzEnv = getenv(z);
+        } else {
+
+            /*
+             *  Make sure we can get the env value (after stripping off
+             *  any trailing directory or file names)
+             */
+            pzEnv = getenv(pzDir);
+        }
+
+        if (pzEnv == NULL) {
+            fprintf(stderr, zWarn, pOpts->pzProgName);
+            fprintf(stderr, zNotDef, pzDir);
+            return NULL;
+        }
+
+        if (pzEndDir == NULL)
+            return pzEnv;
+
+        {
+            size_t sz = strlen(pzEnv) + strlen(pzEndDir) + 2;
+            pzFileName = (char*)AGALOC(sz, "dir name");
+        }
+
+        if (pzFileName == NULL)
+            return NULL;
+
+        *p_free = 1;
+        /*
+         *  Glue together the full name into the allocated memory.
+         *  FIXME: We lose track of this memory.
+         */
+        sprintf(pzFileName, "%s/%s", pzEnv, pzEndDir);
+        return pzFileName;
+    }
+}
+
+
+static char const *
+findFileName(tOptions * pOpts, int * p_free_name)
+{
+    struct stat stBuf;
+    int    free_dir_name = 0;
+
+    char const * pzDir = findDirName(pOpts, &free_dir_name);
+    if (pzDir == NULL)
+        return NULL;
+
+    /*
+     *  See if we can find the specified directory.  We use a once-only loop
+     *  structure so we can bail out early.
+     */
+    if (stat(pzDir, &stBuf) != 0) do {
+        char z[AG_PATH_MAX];
+        char * dirchp;
+
+        /*
+         *  IF we could not, check to see if we got a full
+         *  path to a file name that has not been created yet.
+         */
+        if (errno != ENOENT) {
+        bogus_name:
+            fprintf(stderr, zWarn, pOpts->pzProgName);
+            fprintf(stderr, zNoStat, errno, strerror(errno), pzDir);
+            if (free_dir_name)
+                AGFREE((void*)pzDir);
+            return NULL;
+        }
+
+        /*
+         *  Strip off the last component, stat the remaining string and
+         *  that string must name a directory
+         */
+        dirchp = strrchr(pzDir, DIRCH);
+        if (dirchp == NULL) {
+            stBuf.st_mode = S_IFREG;
+            break; /* found directory -- viz.,  "." */
+        }
+
+        if ((dirchp - pzDir) >= sizeof(z))
+            goto bogus_name;
+
+        memcpy(z, pzDir, (size_t)(dirchp - pzDir));
+        z[dirchp - pzDir] = NUL;
+
+        if ((stat(z, &stBuf) != 0) || ! S_ISDIR(stBuf.st_mode))
+            goto bogus_name;
+        stBuf.st_mode = S_IFREG; /* file within this directory */
+    } while (0);
+
+    /*
+     *  IF what we found was a directory,
+     *  THEN tack on the config file name
+     */
+    if (S_ISDIR(stBuf.st_mode)) {
+        size_t sz = strlen(pzDir) + strlen(pOpts->pzRcName) + 2;
+
+        {
+            char*  pzPath = (char*)AGALOC(sz, "file name");
+#ifdef HAVE_SNPRINTF
+            snprintf(pzPath, sz, "%s/%s", pzDir, pOpts->pzRcName);
+#else
+            sprintf(pzPath, "%s/%s", pzDir, pOpts->pzRcName);
+#endif
+            if (free_dir_name)
+                AGFREE((void*)pzDir);
+            pzDir = pzPath;
+            free_dir_name = 1;
+        }
+
+        /*
+         *  IF we cannot stat the object for any reason other than
+         *     it does not exist, then we bail out
+         */
+        if (stat(pzDir, &stBuf) != 0) {
+            if (errno != ENOENT) {
+                fprintf(stderr, zWarn, pOpts->pzProgName);
+                fprintf(stderr, zNoStat, errno, strerror(errno),
+                        pzDir);
+                AGFREE((void*)pzDir);
+                return NULL;
+            }
+
+            /*
+             *  It does not exist yet, but it will be a regular file
+             */
+            stBuf.st_mode = S_IFREG;
+        }
+    }
+
+    /*
+     *  Make sure that whatever we ultimately found, that it either is
+     *  or will soon be a file.
+     */
+    if (! S_ISREG(stBuf.st_mode)) {
+        fprintf(stderr, zWarn, pOpts->pzProgName);
+        fprintf(stderr, zNotFile, pzDir);
+        if (free_dir_name)
+            AGFREE((void*)pzDir);
+        return NULL;
+    }
+
+    /*
+     *  Get rid of the old file
+     */
+    unlink(pzDir);
+    *p_free_name = free_dir_name;
+    return pzDir;
+}
+
+
+static void
+printEntry(
+    FILE *     fp,
+    tOptDesc * p,
+    tCC*       pzLA )
+{
+    /*
+     *  There is an argument.  Pad the name so values line up.
+     *  Not disabled *OR* this got equivalenced to another opt,
+     *  then use current option name.
+     *  Otherwise, there must be a disablement name.
+     */
+    {
+        char const * pz;
+        if (! DISABLED_OPT(p) || (p->optEquivIndex != NO_EQUIVALENT))
+            pz = p->pz_Name;
+        else
+            pz = p->pz_DisableName;
+
+        fprintf(fp, "%-18s", pz);
+    }
+    /*
+     *  IF the option is numeric only,
+     *  THEN the char pointer is really the number
+     */
+    if (OPTST_GET_ARGTYPE(p->fOptState) == OPARG_TYPE_NUMERIC)
+        fprintf(fp, "  %d\n", (int)(t_word)pzLA);
+
+    /*
+     *  OTHERWISE, FOR each line of the value text, ...
+     */
+    else if (pzLA == NULL)
+        fputc('\n', fp);
+
+    else {
+        fputc(' ', fp); fputc(' ', fp);
+        for (;;) {
+            tCC* pzNl = strchr(pzLA, '\n');
+
+            /*
+             *  IF this is the last line
+             *  THEN bail and print it
+             */
+            if (pzNl == NULL)
+                break;
+
+            /*
+             *  Print the continuation and the text from the current line
+             */
+            (void)fwrite(pzLA, (size_t)(pzNl - pzLA), (size_t)1, fp);
+            pzLA = pzNl+1; /* advance the Last Arg pointer */
+            fputs("\\\n", fp);
+        }
+
+        /*
+         *  Terminate the entry
+         */
+        fputs(pzLA, fp);
+        fputc('\n', fp);
+    }
+}
+
+
+static void
+print_a_value(FILE * fp, int depth, tOptDesc * pOD, tOptionValue const * ovp)
+{
+    static char const bool_atr[]  = "<%1$s type=boolean>%2$s</%1$s>\n";
+    static char const numb_atr[]  = "<%1$s type=integer>0x%2$lX</%1$s>\n";
+    static char const type_atr[]  = "<%s type=%s>";
+    static char const null_atr[]  = "<%s/>\n";
+
+    while (--depth >= 0)
+        putc(' ', fp), putc(' ', fp);
+
+    switch (ovp->valType) {
+    default:
+    case OPARG_TYPE_NONE:
+        fprintf(fp, null_atr, ovp->pzName);
+        break;
+
+    case OPARG_TYPE_STRING:
+        print_a_string(fp, ovp->pzName, ovp->v.strVal);
+        break;
+
+    case OPARG_TYPE_ENUMERATION:
+    case OPARG_TYPE_MEMBERSHIP:
+        if (pOD != NULL) {
+            tAoUI     opt_state = pOD->fOptState;
+            uintptr_t val = pOD->optArg.argEnum;
+            char const * typ = (ovp->valType == OPARG_TYPE_ENUMERATION)
+                ? "keyword" : "set-membership";
+
+            fprintf(fp, type_atr, ovp->pzName, typ);
+
+            /*
+             *  This is a magic incantation that will convert the
+             *  bit flag values back into a string suitable for printing.
+             */
+            (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD );
+            if (pOD->optArg.argString != NULL) {
+                fputs(pOD->optArg.argString, fp);
+
+                if (ovp->valType != OPARG_TYPE_ENUMERATION) {
+                    /*
+                     *  set membership strings get allocated
+                     */
+                    AGFREE((void*)pOD->optArg.argString);
+                }
+            }
+
+            pOD->optArg.argEnum = val;
+            pOD->fOptState = opt_state;
+            fprintf(fp, close_xml, ovp->pzName);
+            break;
+        }
+        /* FALLTHROUGH */
+
+    case OPARG_TYPE_NUMERIC:
+        fprintf(fp, numb_atr, ovp->pzName, ovp->v.longVal);
+        break;
+
+    case OPARG_TYPE_BOOLEAN:
+        fprintf(fp, bool_atr, ovp->pzName,
+                ovp->v.boolVal ? "true" : "false");
+        break;
+
+    case OPARG_TYPE_HIERARCHY:
+        printValueList(fp, ovp->pzName, ovp->v.nestVal);
+        break;
+    }
+}
+
+
+static void
+print_a_string(FILE * fp, char const * name, char const * pz)
+{
+    static char const open_atr[]  = "<%s>";
+
+    fprintf(fp, open_atr, name);
+    for (;;) {
+        int ch = ((int)*(pz++)) & 0xFF;
+
+        switch (ch) {
+        case NUL: goto string_done;
+
+        case '&':
+        case '<':
+        case '>':
+#if __GNUC__ >= 4
+        case 1 ... (' ' - 1):
+        case ('~' + 1) ... 0xFF:
+#endif
+            emit_special_char(fp, ch);
+            break;
+
+        default:
+#if __GNUC__ < 4
+            if (  ((ch >= 1) && (ch <= (' ' - 1)))
+               || ((ch >= ('~' + 1)) && (ch <= 0xFF)) ) {
+                emit_special_char(fp, ch);
+                break;
+            }
+#endif
+            putc(ch, fp);
+        }
+    } string_done:;
+    fprintf(fp, close_xml, name);
+}
+
+
+static void
+printValueList(FILE * fp, char const * name, tArgList * al)
+{
+    static int depth = 1;
+
+    int sp_ct;
+    int opt_ct;
+    void ** opt_list;
+
+    if (al == NULL)
+        return;
+    opt_ct   = al->useCt;
+    opt_list = (void **)al->apzArgs;
+
+    if (opt_ct <= 0) {
+        fprintf(fp, "<%s/>\n", name);
+        return;
+    }
+
+    fprintf(fp, "<%s type=nested>\n", name);
+
+    depth++;
+    while (--opt_ct >= 0) {
+        tOptionValue const * ovp = *(opt_list++);
+
+        print_a_value(fp, depth, NULL, ovp);
+    }
+    depth--;
+
+    for (sp_ct = depth; --sp_ct >= 0;)
+        putc(' ', fp), putc(' ', fp);
+    fprintf(fp, "</%s>\n", name);
+}
+
+
+static void
+printHierarchy(FILE * fp, tOptDesc * p)
+{
+    int opt_ct;
+    tArgList * al = p->optCookie;
+    void ** opt_list;
+
+    if (al == NULL)
+        return;
+
+    opt_ct   = al->useCt;
+    opt_list = (void **)al->apzArgs;
+
+    if (opt_ct <= 0)
+        return;
+
+    do  {
+        tOptionValue const * base = *(opt_list++);
+        tOptionValue const * ovp = optionGetValue(base, NULL);
+
+        if (ovp == NULL)
+            continue;
+
+        fprintf(fp, "<%s type=nested>\n", p->pz_Name);
+
+        do  {
+            print_a_value(fp, 1, p, ovp);
+
+        } while (ovp = optionNextValue(base, ovp),
+                 ovp != NULL);
+
+        fprintf(fp, "</%s>\n", p->pz_Name);
+    } while (--opt_ct > 0);
+}
+
+
+static FILE *
+openSaveFile(tOptions* pOpts)
+{
+    FILE*     fp;
+
+    {
+        int   free_name = 0;
+        tCC*  pzFName = findFileName(pOpts, &free_name);
+        if (pzFName == NULL)
+            return NULL;
+
+        fp = fopen(pzFName, "w" FOPEN_BINARY_FLAG);
+        if (fp == NULL) {
+            fprintf(stderr, zWarn, pOpts->pzProgName);
+            fprintf(stderr, zNoCreat, errno, strerror(errno), pzFName);
+            if (free_name)
+                AGFREE((void*) pzFName );
+            return fp;
+        }
+
+        if (free_name)
+            AGFREE((void*)pzFName);
+    }
+
+    {
+        char const*  pz = pOpts->pzUsageTitle;
+        fputs("#  ", fp);
+        do { fputc(*pz, fp); } while (*(pz++) != '\n');
+    }
+
+    {
+        time_t  timeVal = time(NULL);
+        char*   pzTime  = ctime(&timeVal);
+
+        fprintf(fp, zPresetFile, pzTime);
+#ifdef HAVE_ALLOCATED_CTIME
+        /*
+         *  The return values for ctime(), localtime(), and gmtime()
+         *  normally point to static data that is overwritten by each call.
+         *  The test to detect allocated ctime, so we leak the memory.
+         */
+        AGFREE((void*)pzTime);
+#endif
+    }
+
+    return fp;
+}
+
+static void
+printNoArgOpt(FILE * fp, tOptDesc * p, tOptDesc * pOD)
+{
+    /*
+     * The aliased to argument indicates whether or not the option
+     * is "disabled".  However, the original option has the name
+     * string, so we get that there, not with "p".
+     */
+    char const * pznm =
+        (DISABLED_OPT(p)) ? pOD->pz_DisableName : pOD->pz_Name;
+    /*
+     *  If the option was disabled and the disablement name is NULL,
+     *  then the disablement was caused by aliasing.
+     *  Use the name as the string to emit.
+     */
+    if (pznm == NULL)
+        pznm = pOD->pz_Name;
+
+    fprintf(fp, "%s\n", pznm);
+}
+
+static void
+printStringArg(FILE * fp, tOptDesc * pOD)
+{
+    if (pOD->fOptState & OPTST_STACKED) {
+        tArgList*  pAL = (tArgList*)pOD->optCookie;
+        int        uct = pAL->useCt;
+        tCC**      ppz = pAL->apzArgs;
+
+        /*
+         *  un-disable multiple copies of disabled options.
+         */
+        if (uct > 1)
+            pOD->fOptState &= ~OPTST_DISABLED;
+
+        while (uct-- > 0)
+            printEntry(fp, pOD, *(ppz++));
+    } else {
+        printEntry(fp, pOD, pOD->optArg.argString);
+    }
+}
+
+static void
+printEnumArg(FILE * fp, tOptDesc * pOD)
+{
+    uintptr_t val = pOD->optArg.argEnum;
+
+    /*
+     *  This is a magic incantation that will convert the
+     *  bit flag values back into a string suitable for printing.
+     */
+    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
+    printEntry(fp, pOD, (void*)(pOD->optArg.argString));
+
+    pOD->optArg.argEnum = val;
+}
+
+static void
+printSetMemberArg(FILE * fp, tOptDesc * pOD)
+{
+    uintptr_t val = pOD->optArg.argEnum;
+
+    /*
+     *  This is a magic incantation that will convert the
+     *  bit flag values back into a string suitable for printing.
+     */
+    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
+    printEntry(fp, pOD, (void*)(pOD->optArg.argString));
+
+    if (pOD->optArg.argString != NULL) {
+        /*
+         *  set membership strings get allocated
+         */
+        AGFREE((void*)pOD->optArg.argString);
+        pOD->fOptState &= ~OPTST_ALLOC_ARG;
+    }
+
+    pOD->optArg.argEnum = val;
+}
+
+static void
+printFileArg(FILE * fp, tOptDesc * pOD, tOptions* pOpts)
+{
+    /*
+     *  If the cookie is not NULL, then it has the file name, period.
+     *  Otherwise, if we have a non-NULL string argument, then....
+     */
+    if (pOD->optCookie != NULL)
+        printEntry(fp, pOD, pOD->optCookie);
+
+    else if (HAS_originalOptArgArray(pOpts)) {
+        char const * orig =
+            pOpts->originalOptArgArray[pOD->optIndex].argString;
+
+        if (pOD->optArg.argString == orig)
+            return;
+
+        printEntry(fp, pOD, pOD->optArg.argString);
+    }
+}
+
+
+/*=export_func  optionSaveFile
+ *
+ * what:  saves the option state to a file
+ *
+ * arg:   tOptions*,   pOpts,  program options descriptor
+ *
+ * doc:
+ *
+ * This routine will save the state of option processing to a file.  The name
+ * of that file can be specified with the argument to the @code{--save-opts}
+ * option, or by appending the @code{rcfile} attribute to the last
+ * @code{homerc} attribute.  If no @code{rcfile} attribute was specified, it
+ * will default to @code{.@i{programname}rc}.  If you wish to specify another
+ * file, you should invoke the @code{SET_OPT_SAVE_OPTS(@i{filename})} macro.
+ *
+ * The recommend usage is as follows:
+ * @example
+ *    optionProcess(&progOptions, argc, argv);
+ *    if (i_want_a_non_standard_place_for_this)
+ *        SET_OPT_SAVE_OPTS("myfilename");
+ *    optionSaveFile(&progOptions);
+ * @end example
+ *
+ * err:
+ *
+ * If no @code{homerc} file was specified, this routine will silently return
+ * and do nothing.  If the output file cannot be created or updated, a message
+ * will be printed to @code{stderr} and the routine will return.
+=*/
+void
+optionSaveFile(tOptions* pOpts)
+{
+    tOptDesc* pOD;
+    int       ct;
+    FILE*     fp = openSaveFile(pOpts);
+
+    if (fp == NULL)
+        return;
+
+    /*
+     *  FOR each of the defined options, ...
+     */
+    ct  = pOpts->presetOptCt;
+    pOD = pOpts->pOptDesc;
+    do  {
+        tOptDesc*  p;
+
+        /*
+         *  IF    the option has not been defined
+         *     OR it does not take an initialization value
+         *     OR it is equivalenced to another option
+         *  THEN continue (ignore it)
+         *
+         *  Equivalenced options get picked up when the equivalenced-to
+         *  option is processed.
+         */
+        if (UNUSED_OPT(pOD))
+            continue;
+
+        if ((pOD->fOptState & OPTST_DO_NOT_SAVE_MASK) != 0)
+            continue;
+
+        if (  (pOD->optEquivIndex != NO_EQUIVALENT)
+           && (pOD->optEquivIndex != pOD->optIndex))
+            continue;
+
+        /*
+         *  The option argument data are found at the equivalenced-to option,
+         *  but the actual option argument type comes from the original
+         *  option descriptor.  Be careful!
+         */
+        p = ((pOD->fOptState & OPTST_EQUIVALENCE) != 0)
+            ? (pOpts->pOptDesc + pOD->optActualIndex) : pOD;
+
+        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_NONE:
+            printNoArgOpt(fp, p, pOD);
+            break;
+
+        case OPARG_TYPE_NUMERIC:
+            printEntry(fp, p, (void*)(p->optArg.argInt));
+            break;
+
+        case OPARG_TYPE_STRING:
+            printStringArg(fp, p);
+            break;
+
+        case OPARG_TYPE_ENUMERATION:
+            printEnumArg(fp, p);
+            break;
+
+        case OPARG_TYPE_MEMBERSHIP:
+            printSetMemberArg(fp, p);
+            break;
+
+        case OPARG_TYPE_BOOLEAN:
+            printEntry(fp, p, p->optArg.argBool ? "true" : "false");
+            break;
+
+        case OPARG_TYPE_HIERARCHY:
+            printHierarchy(fp, p);
+            break;
+
+        case OPARG_TYPE_FILE:
+            printFileArg(fp, p, pOpts);
+            break;
+
+        default:
+            break; /* cannot handle - skip it */
+        }
+    } while (pOD++, (--ct > 0));
+
+    fclose(fp);
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/save.c */
diff --git a/libopts/sort.c b/libopts/sort.c
new file mode 100644 (file)
index 0000000..89d716a
--- /dev/null
@@ -0,0 +1,336 @@
+
+/*
+ * \file sort.c
+ *
+ * Time-stamp:      "2011-05-24 18:07:14 bkorb"
+ *
+ *  This module implements argument sorting.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static tSuccess
+mustHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
+              char** ppzOpts, int* pOptsIdx);
+
+static tSuccess
+mayHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
+             char** ppzOpts, int* pOptsIdx);
+
+static tSuccess
+checkShortOpts(tOptions* pOpts, char* pzArg, tOptState* pOS,
+               char** ppzOpts, int* pOptsIdx);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*
+ *  "mustHandleArg" and "mayHandleArg" are really similar.  The biggest
+ *  difference is that "may" will consume the next argument only if it
+ *  does not start with a hyphen and "must" will consume it, hyphen or not.
+ */
+static tSuccess
+mustHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
+              char** ppzOpts, int* pOptsIdx)
+{
+    /*
+     *  An option argument is required.  Long options can either have
+     *  a separate command line argument, or an argument attached by
+     *  the '=' character.  Figure out which.
+     */
+    switch (pOS->optType) {
+    case TOPT_SHORT:
+        /*
+         *  See if an arg string follows the flag character.  If not,
+         *  the next arg must be the option argument.
+         */
+        if (*pzArg != NUL)
+            return SUCCESS;
+        break;
+
+    case TOPT_LONG:
+        /*
+         *  See if an arg string has already been assigned (glued on
+         *  with an `=' character).  If not, the next is the opt arg.
+         */
+        if (pOS->pzOptArg != NULL)
+            return SUCCESS;
+        break;
+
+    default:
+        return FAILURE;
+    }
+    if (pOpts->curOptIdx >= pOpts->origArgCt)
+        return FAILURE;
+
+    ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+    return SUCCESS;
+}
+
+static tSuccess
+mayHandleArg(tOptions* pOpts, char* pzArg, tOptState* pOS,
+             char** ppzOpts, int* pOptsIdx)
+{
+    /*
+     *  An option argument is optional.
+     */
+    switch (pOS->optType) {
+    case TOPT_SHORT:
+        /*
+         *  IF nothing is glued on after the current flag character,
+         *  THEN see if there is another argument.  If so and if it
+         *  does *NOT* start with a hyphen, then it is the option arg.
+         */
+        if (*pzArg != NUL)
+            return SUCCESS;
+        break;
+
+    case TOPT_LONG:
+        /*
+         *  Look for an argument if we don't already have one (glued on
+         *  with a `=' character)
+         */
+        if (pOS->pzOptArg != NULL)
+            return SUCCESS;
+        break;
+
+    default:
+        return FAILURE;
+    }
+    if (pOpts->curOptIdx >= pOpts->origArgCt)
+        return PROBLEM;
+
+    pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
+    if (*pzArg != '-')
+        ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+    return SUCCESS;
+}
+
+/*
+ *  Process a string of short options glued together.  If the last one
+ *  does or may take an argument, the do the argument processing and leave.
+ */
+static tSuccess
+checkShortOpts(tOptions* pOpts, char* pzArg, tOptState* pOS,
+               char** ppzOpts, int* pOptsIdx)
+{
+    while (*pzArg != NUL) {
+        if (FAILED(opt_find_short(pOpts, (tAoUC)*pzArg, pOS)))
+            return FAILURE;
+
+        /*
+         *  See if we can have an arg.
+         */
+        if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
+            pzArg++;
+
+        } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
+            /*
+             *  Take an argument if it is not attached and it does not
+             *  start with a hyphen.
+             */
+            if (pzArg[1] != NUL)
+                return SUCCESS;
+
+            pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
+            if (*pzArg != '-')
+                ppzOpts[ (*pOptsIdx)++ ] =
+                    pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+            return SUCCESS;
+
+        } else {
+            /*
+             *  IF we need another argument, be sure it is there and
+             *  take it.
+             */
+            if (pzArg[1] == NUL) {
+                if (pOpts->curOptIdx >= pOpts->origArgCt)
+                    return FAILURE;
+                ppzOpts[ (*pOptsIdx)++ ] =
+                    pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+            }
+            return SUCCESS;
+        }
+    }
+    return SUCCESS;
+}
+
+/*
+ *  If the program wants sorted options (separated operands and options),
+ *  then this routine will to the trick.
+ */
+LOCAL void
+optionSort(tOptions* pOpts)
+{
+    char** ppzOpts;
+    char** ppzOpds;
+    int    optsIdx = 0;
+    int    opdsIdx = 0;
+
+    tOptState os = OPTSTATE_INITIALIZER(DEFINED);
+
+    /*
+     *  Disable for POSIX conformance, or if there are no operands.
+     */
+    if (  (getenv("POSIXLY_CORRECT") != NULL)
+       || NAMED_OPTS(pOpts))
+        return;
+
+    /*
+     *  Make sure we can allocate two full-sized arg vectors.
+     */
+    ppzOpts = malloc(pOpts->origArgCt * sizeof(char*));
+    if (ppzOpts == NULL)
+        goto exit_no_mem;
+
+    ppzOpds = malloc(pOpts->origArgCt * sizeof(char*));
+    if (ppzOpds == NULL) {
+        free(ppzOpts);
+        goto exit_no_mem;
+    }
+
+    pOpts->curOptIdx = 1;
+    pOpts->pzCurOpt  = NULL;
+
+    /*
+     *  Now, process all the options from our current position onward.
+     *  (This allows interspersed options and arguments for the few
+     *  non-standard programs that require it.)
+     */
+    for (;;) {
+        char* pzArg;
+        tSuccess res;
+
+        /*
+         *  If we're out of arguments, we're done.  Join the option and
+         *  operand lists into the original argument vector.
+         */
+        if (pOpts->curOptIdx >= pOpts->origArgCt) {
+            errno = 0;
+            goto joinLists;
+        }
+
+        pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
+        if (*pzArg != '-') {
+            ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+            continue;
+        }
+
+        switch (pzArg[1]) {
+        case NUL:
+            /*
+             *  A single hyphen is an operand.
+             */
+            ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+            continue;
+
+        case '-':
+            /*
+             *  Two consecutive hypens.  Put them on the options list and then
+             *  _always_ force the remainder of the arguments to be operands.
+             */
+            if (pzArg[2] == NUL) {
+                ppzOpts[ optsIdx++ ] =
+                    pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+                goto restOperands;
+            }
+            res = opt_find_long(pOpts, pzArg+2, &os);
+            break;
+
+        default:
+            /*
+             *  If short options are not allowed, then do long
+             *  option processing.  Otherwise the character must be a
+             *  short (i.e. single character) option.
+             */
+            if ((pOpts->fOptSet & OPTPROC_SHORTOPT) == 0) {
+                res = opt_find_long(pOpts, pzArg+1, &os);
+            } else {
+                res = opt_find_short(pOpts, (tAoUC)pzArg[1], &os);
+            }
+            break;
+        }
+        if (FAILED(res)) {
+            errno = EINVAL;
+            goto freeTemps;
+        }
+
+        /*
+         *  We've found an option.  Add the argument to the option list.
+         *  Next, we have to see if we need to pull another argument to be
+         *  used as the option argument.
+         */
+        ppzOpts[ optsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+
+        if (OPTST_GET_ARGTYPE(os.pOD->fOptState) == OPARG_TYPE_NONE) {
+            /*
+             *  No option argument.  If we have a short option here,
+             *  then scan for short options until we get to the end
+             *  of the argument string.
+             */
+            if (  (os.optType == TOPT_SHORT)
+               && FAILED(checkShortOpts(pOpts, pzArg+2, &os, ppzOpts,
+                                        &optsIdx)) )  {
+                errno = EINVAL;
+                goto freeTemps;
+            }
+
+        } else if (os.pOD->fOptState & OPTST_ARG_OPTIONAL) {
+            switch (mayHandleArg(pOpts, pzArg+2, &os, ppzOpts, &optsIdx)) {
+            case FAILURE: errno = EIO; goto freeTemps;
+            case PROBLEM: errno = 0;   goto joinLists;
+            }
+
+        } else {
+            switch (mustHandleArg(pOpts, pzArg+2, &os, ppzOpts, &optsIdx)) {
+            case PROBLEM:
+            case FAILURE: errno = EIO; goto freeTemps;
+            }
+        }
+    } /* for (;;) */
+
+ restOperands:
+    while (pOpts->curOptIdx < pOpts->origArgCt)
+        ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
+
+ joinLists:
+    if (optsIdx > 0)
+        memcpy(pOpts->origArgVect + 1, ppzOpts, optsIdx * sizeof(char*));
+    if (opdsIdx > 0)
+        memcpy(pOpts->origArgVect + 1 + optsIdx, ppzOpds,
+               opdsIdx * sizeof(char*));
+
+ freeTemps:
+    free(ppzOpts);
+    free(ppzOpds);
+    return;
+
+ exit_no_mem:
+    errno = ENOMEM;
+    return;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/sort.c */
diff --git a/libopts/stack.c b/libopts/stack.c
new file mode 100644 (file)
index 0000000..d930772
--- /dev/null
@@ -0,0 +1,264 @@
+
+/**
+ * \file stack.c
+ *
+ *  Time-stamp:      "2010-07-17 10:42:27 bkorb"
+ *
+ *  This is a special option processing routine that will save the
+ *  argument to an option in a FIFO queue.
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+#ifdef WITH_LIBREGEX
+#  include REGEX_HEADER
+#endif
+
+/*=export_func  optionUnstackArg
+ * private:
+ *
+ * what:  Remove option args from a stack
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Invoked for options that are equivalenced to stacked options.
+=*/
+void
+optionUnstackArg(
+    tOptions*  pOpts,
+    tOptDesc*  pOptDesc )
+{
+    int       res;
+
+    tArgList* pAL;
+
+    if ((pOptDesc->fOptState & OPTST_RESET) != 0)
+        return;
+    pAL = (tArgList*)pOptDesc->optCookie;
+
+    /*
+     *  IF we don't have any stacked options,
+     *  THEN indicate that we don't have any of these options
+     */
+    if (pAL == NULL) {
+        pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
+        if ((pOptDesc->fOptState & OPTST_INITENABLED) == 0)
+            pOptDesc->fOptState |= OPTST_DISABLED;
+        return;
+    }
+
+#ifdef WITH_LIBREGEX
+    {
+        regex_t   re;
+        int       i, ct, dIdx;
+
+        if (regcomp(&re, pOptDesc->optArg.argString, REG_NOSUB) != 0)
+            return;
+
+        /*
+         *  search the list for the entry(s) to remove.  Entries that
+         *  are removed are *not* copied into the result.  The source
+         *  index is incremented every time.  The destination only when
+         *  we are keeping a define.
+         */
+        for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
+            tCC*      pzSrc = pAL->apzArgs[ i ];
+            char*     pzEq  = strchr(pzSrc, '=');
+
+            if (pzEq != NULL)
+                *pzEq = NUL;
+
+            res = regexec(&re, pzSrc, (size_t)0, NULL, 0);
+            switch (res) {
+            case 0:
+                /*
+                 *  Remove this entry by reducing the in-use count
+                 *  and *not* putting the string pointer back into
+                 *  the list.
+                 */
+                AGFREE(pzSrc);
+                pAL->useCt--;
+                break;
+
+            default:
+            case REG_NOMATCH:
+                if (pzEq != NULL)
+                    *pzEq = '=';
+
+                /*
+                 *  IF we have dropped an entry
+                 *  THEN we have to move the current one.
+                 */
+                if (dIdx != i)
+                    pAL->apzArgs[ dIdx ] = pzSrc;
+                dIdx++;
+            }
+        }
+
+        regfree(&re);
+    }
+#else  /* not WITH_LIBREGEX */
+    {
+        int i, ct, dIdx;
+
+        /*
+         *  search the list for the entry(s) to remove.  Entries that
+         *  are removed are *not* copied into the result.  The source
+         *  index is incremented every time.  The destination only when
+         *  we are keeping a define.
+         */
+        for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
+            tCC*      pzSrc = pAL->apzArgs[ i ];
+            char*     pzEq  = strchr(pzSrc, '=');
+
+            if (pzEq != NULL)
+                *pzEq = NUL;
+
+            if (strcmp(pzSrc, pOptDesc->optArg.argString) == 0) {
+                /*
+                 *  Remove this entry by reducing the in-use count
+                 *  and *not* putting the string pointer back into
+                 *  the list.
+                 */
+                AGFREE(pzSrc);
+                pAL->useCt--;
+            } else {
+                if (pzEq != NULL)
+                    *pzEq = '=';
+
+                /*
+                 *  IF we have dropped an entry
+                 *  THEN we have to move the current one.
+                 */
+                if (dIdx != i)
+                    pAL->apzArgs[ dIdx ] = pzSrc;
+                dIdx++;
+            }
+        }
+    }
+#endif /* WITH_LIBREGEX */
+    /*
+     *  IF we have unstacked everything,
+     *  THEN indicate that we don't have any of these options
+     */
+    if (pAL->useCt == 0) {
+        pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
+        if ((pOptDesc->fOptState & OPTST_INITENABLED) == 0)
+            pOptDesc->fOptState |= OPTST_DISABLED;
+        AGFREE((void*)pAL);
+        pOptDesc->optCookie = NULL;
+    }
+}
+
+
+/*
+ *  Put an entry into an argument list.  The first argument points to
+ *  a pointer to the argument list structure.  It gets passed around
+ *  as an opaque address.
+ */
+LOCAL void
+addArgListEntry(void** ppAL, void* entry)
+{
+    tArgList* pAL = *(void**)ppAL;
+
+    /*
+     *  IF we have never allocated one of these,
+     *  THEN allocate one now
+     */
+    if (pAL == NULL) {
+        pAL = (tArgList*)AGALOC(sizeof(*pAL), "new option arg stack");
+        if (pAL == NULL)
+            return;
+        pAL->useCt   = 0;
+        pAL->allocCt = MIN_ARG_ALLOC_CT;
+        *ppAL = (void*)pAL;
+    }
+
+    /*
+     *  ELSE if we are out of room
+     *  THEN make it bigger
+     */
+    else if (pAL->useCt >= pAL->allocCt) {
+        size_t sz = sizeof(*pAL);
+        pAL->allocCt += INCR_ARG_ALLOC_CT;
+
+        /*
+         *  The base structure contains space for MIN_ARG_ALLOC_CT
+         *  pointers.  We subtract it off to find our augment size.
+         */
+        sz += sizeof(char*) * (pAL->allocCt - MIN_ARG_ALLOC_CT);
+        pAL = (tArgList*)AGREALOC((void*)pAL, sz, "expanded opt arg stack");
+        if (pAL == NULL)
+            return;
+        *ppAL = (void*)pAL;
+    }
+
+    /*
+     *  Insert the new argument into the list
+     */
+    pAL->apzArgs[ (pAL->useCt)++ ] = entry;
+}
+
+
+/*=export_func  optionStackArg
+ * private:
+ *
+ * what:  put option args on a stack
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Keep an entry-ordered list of option arguments.
+=*/
+void
+optionStackArg(
+    tOptions*  pOpts,
+    tOptDesc*  pOD )
+{
+    char * pz;
+
+    if ((pOD->fOptState & OPTST_RESET) != 0) {
+        tArgList* pAL = (void*)pOD->optCookie;
+        int ix;
+        if (pAL == NULL)
+            return;
+
+        ix = pAL->useCt;
+        while (--ix >= 0)
+            AGFREE(pAL->apzArgs[ix]);
+        AGFREE(pAL);
+
+    } else {
+        if (pOD->optArg.argString == NULL)
+            return;
+
+        AGDUPSTR(pz, pOD->optArg.argString, "stack arg");
+        addArgListEntry(&(pOD->optCookie), (void*)pz);
+    }
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/stack.c */
diff --git a/libopts/streqvcmp.c b/libopts/streqvcmp.c
new file mode 100644 (file)
index 0000000..d2cb65d
--- /dev/null
@@ -0,0 +1,267 @@
+
+/**
+ * \file streqvcmp.c
+ *
+ * Time-stamp:      "2010-07-17 10:16:24 bkorb"
+ *
+ *  String Equivalence Comparison
+ *
+ *  These routines allow any character to be mapped to any other
+ *  character before comparison.  In processing long option names,
+ *  the characters "-", "_" and "^" all need to be equivalent
+ *  (because they are treated so by different development environments).
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ *
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+    0x00, 0x01, 0x02, 0x03,  0x04, 0x05, 0x06, '\a',
+    '\b', '\t', '\n', '\v',  '\f', '\r', 0x0E, 0x0F,
+    0x10, 0x11, 0x12, 0x13,  0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1A, 0x1B,  0x1C, 0x1D, 0x1E, 0x1F,
+
+    ' ',  '!',  '"',  '#',   '$',  '%',  '&',  '\'',
+    '(',  ')',  '*',  '+',   ',',  '-',  '.',  '/',
+    '0',  '1',  '2',  '3',   '4',  '5',  '6',  '7',
+    '8',  '9',  ':',  ';',   '<',  '=',  '>',  '?',
+
+    '@',  'a',  'b',  'c',   'd',  'e',  'f',  'g',
+    'h',  'i',  'j',  'k',   'l',  'm',  'n',  'o',
+    'p',  'q',  'r',  's',   't',  'u',  'v',  'w',
+    'x',  'y',  'z',  '[',   '\\', ']',  '^',  '_',
+    '`',  'a',  'b',  'c',   'd',  'e',  'f',  'g',
+    'h',  'i',  'j',  'k',   'l',  'm',  'n',  'o',
+    'p',  'q',  'r',  's',   't',  'u',  'v',  'w',
+    'x',  'y',  'z',  '{',   '|',  '}',  '~',  0x7f,
+
+    0x80, 0x81, 0x82, 0x83,  0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8A, 0x8B,  0x8C, 0x8D, 0x8E, 0x8F,
+    0x90, 0x91, 0x92, 0x93,  0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9A, 0x9B,  0x9C, 0x9D, 0x9E, 0x9F,
+    0xA0, 0xA1, 0xA2, 0xA3,  0xA4, 0xA5, 0xA6, 0xA7,
+    0xA8, 0xA9, 0xAA, 0xAB,  0xAC, 0xAD, 0xAE, 0xAF,
+    0xB0, 0xB1, 0xB2, 0xB3,  0xB4, 0xB5, 0xB6, 0xB7,
+    0xB8, 0xB9, 0xBA, 0xBB,  0xBC, 0xBD, 0xBE, 0xBF,
+
+    0xC0, 0xC1, 0xC2, 0xC3,  0xC4, 0xC5, 0xC6, 0xC7,
+    0xC8, 0xC9, 0xCA, 0xCB,  0xCC, 0xCD, 0xCE, 0xCF,
+    0xD0, 0xD1, 0xD2, 0xD3,  0xD4, 0xD5, 0xD6, 0xD7,
+    0xD8, 0xD9, 0xDA, 0xDB,  0xDC, 0xDD, 0xDE, 0xDF,
+    0xE0, 0xE1, 0xE2, 0xE3,  0xE4, 0xE5, 0xE6, 0xE7,
+    0xE8, 0xE9, 0xEA, 0xEB,  0xEC, 0xED, 0xEE, 0xEF,
+    0xF0, 0xF1, 0xF2, 0xF3,  0xF4, 0xF5, 0xF6, 0xF7,
+    0xF8, 0xF9, 0xFA, 0xFB,  0xFC, 0xFD, 0xFE, 0xFF,
+};
+
+
+/*=export_func strneqvcmp
+ *
+ * what: compare two strings with an equivalence mapping
+ *
+ * arg:  + char const* + str1 + first string +
+ * arg:  + char const* + str2 + second string +
+ * arg:  + int         + ct   + compare length +
+ *
+ * ret_type:  int
+ * ret_desc:  the difference between two differing characters
+ *
+ * doc:
+ *
+ * Using a character mapping, two strings are compared for "equivalence".
+ * Each input character is mapped to a comparison character and the
+ * mapped-to characters are compared for the two NUL terminated input strings.
+ * The comparison is limited to @code{ct} bytes.
+ * This function name is mapped to option_strneqvcmp so as to not conflict
+ * with the POSIX name space.
+ *
+ * err:  none checked.  Caller responsible for seg faults.
+=*/
+int
+strneqvcmp(tCC* s1, tCC* s2, int ct)
+{
+    for (; ct > 0; --ct) {
+        unsigned char u1 = (unsigned char) *s1++;
+        unsigned char u2 = (unsigned char) *s2++;
+        int dif = charmap[ u1 ] - charmap[ u2 ];
+
+        if (dif != 0)
+            return dif;
+
+        if (u1 == NUL)
+            return 0;
+    }
+
+    return 0;
+}
+
+
+/*=export_func streqvcmp
+ *
+ * what: compare two strings with an equivalence mapping
+ *
+ * arg:  + char const* + str1 + first string +
+ * arg:  + char const* + str2 + second string +
+ *
+ * ret_type:  int
+ * ret_desc:  the difference between two differing characters
+ *
+ * doc:
+ *
+ * Using a character mapping, two strings are compared for "equivalence".
+ * Each input character is mapped to a comparison character and the
+ * mapped-to characters are compared for the two NUL terminated input strings.
+ * This function name is mapped to option_streqvcmp so as to not conflict
+ * with the POSIX name space.
+ *
+ * err:  none checked.  Caller responsible for seg faults.
+=*/
+int
+streqvcmp(tCC* s1, tCC* s2)
+{
+    for (;;) {
+        unsigned char u1 = (unsigned char) *s1++;
+        unsigned char u2 = (unsigned char) *s2++;
+        int dif = charmap[ u1 ] - charmap[ u2 ];
+
+        if (dif != 0)
+            return dif;
+
+        if (u1 == NUL)
+            return 0;
+    }
+}
+
+
+/*=export_func streqvmap
+ *
+ * what: Set the character mappings for the streqv functions
+ *
+ * arg:  + char + From + Input character +
+ * arg:  + char + To   + Mapped-to character +
+ * arg:  + int  + ct   + compare length +
+ *
+ * doc:
+ *
+ * Set the character mapping.  If the count (@code{ct}) is set to zero, then
+ * the map is cleared by setting all entries in the map to their index
+ * value.  Otherwise, the "@code{From}" character is mapped to the "@code{To}"
+ * character.  If @code{ct} is greater than 1, then @code{From} and @code{To}
+ * are incremented and the process repeated until @code{ct} entries have been
+ * set. For example,
+ * @example
+ *    streqvmap('a', 'A', 26);
+ * @end example
+ * @noindent
+ * will alter the mapping so that all English lower case letters
+ * will map to upper case.
+ *
+ * This function name is mapped to option_streqvmap so as to not conflict
+ * with the POSIX name space.
+ *
+ * err:  none.
+=*/
+void
+streqvmap(char From, char To, int ct)
+{
+    if (ct == 0) {
+        ct = sizeof(charmap) - 1;
+        do  {
+            charmap[ ct ] = ct;
+        } while (--ct >= 0);
+    }
+
+    else {
+        int  chTo   = (int)To   & 0xFF;
+        int  chFrom = (int)From & 0xFF;
+
+        do  {
+            charmap[ chFrom ] = (unsigned)chTo;
+            chFrom++;
+            chTo++;
+            if ((chFrom >= sizeof(charmap)) || (chTo >= sizeof(charmap)))
+                break;
+        } while (--ct > 0);
+    }
+}
+
+
+/*=export_func strequate
+ *
+ * what: map a list of characters to the same value
+ *
+ * arg:  + char const* + ch_list + characters to equivalence +
+ *
+ * doc:
+ *
+ * Each character in the input string get mapped to the first character
+ * in the string.
+ * This function name is mapped to option_strequate so as to not conflict
+ * with the POSIX name space.
+ *
+ * err:  none.
+=*/
+void
+strequate(char const* s)
+{
+    if ((s != NULL) && (*s != NUL)) {
+        unsigned char equiv = (unsigned)*s;
+        while (*s != NUL)
+            charmap[ (unsigned)*(s++) ] = equiv;
+    }
+}
+
+
+/*=export_func strtransform
+ *
+ * what: convert a string into its mapped-to value
+ *
+ * arg:  + char*       + dest + output string +
+ * arg:  + char const* + src  + input string +
+ *
+ * doc:
+ *
+ * Each character in the input string is mapped and the mapped-to
+ * character is put into the output.
+ * This function name is mapped to option_strtransform so as to not conflict
+ * with the POSIX name space.
+ *
+ * The source and destination may be the same.
+ *
+ * err:  none.
+=*/
+void
+strtransform(char* d, char const* s)
+{
+    do  {
+        *(d++) = (char)charmap[ (unsigned)*s ];
+    } while (*(s++) != NUL);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/streqvcmp.c */
diff --git a/libopts/text_mmap.c b/libopts/text_mmap.c
new file mode 100644 (file)
index 0000000..4a7a9df
--- /dev/null
@@ -0,0 +1,366 @@
+/**
+ * @file text_mmap.c
+ *
+ * Map a text file, ensuring the text always has an ending NUL byte.
+ *
+ * Time-stamp:      "2011-06-25 11:42:22 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+#if defined(HAVE_MMAP)
+#  ifndef      MAP_ANONYMOUS
+#    ifdef     MAP_ANON
+#      define  MAP_ANONYMOUS   MAP_ANON
+#    endif
+#  endif
+
+#  if ! defined(MAP_ANONYMOUS) && ! defined(HAVE_DEV_ZERO)
+     /*
+      * We must have either /dev/zero or anonymous mapping for
+      * this to work.
+      */
+#    undef HAVE_MMAP
+
+#  else
+#    ifdef _SC_PAGESIZE
+#      define GETPAGESIZE() sysconf(_SC_PAGESIZE)
+#    else
+#      define GETPAGESIZE() getpagesize()
+#    endif
+#  endif
+#endif
+
+/*
+ *  Some weird systems require that a specifically invalid FD number
+ *  get passed in as an argument value.  Which value is that?  Well,
+ *  as everybody knows, if open(2) fails, it returns -1, so that must
+ *  be the value.  :)
+ */
+#define AO_INVALID_FD  -1
+
+#define FILE_WRITABLE(_prt,_flg) \
+        (   (_prt & PROT_WRITE) \
+         && ((_flg & (MAP_SHARED|MAP_PRIVATE)) == MAP_SHARED))
+#define MAP_FAILED_PTR ((void*)MAP_FAILED)
+
+/**
+ * Load the contents of a text file.  There are two separate implementations,
+ * depending up on whether mmap(3) is available.
+ *
+ *  If not available, malloc the file length plus one byte.  Read it in
+ *  and NUL terminate.
+ *
+ *  If available, first check to see if the text file size is a multiple of a
+ *  page size.  If it is, map the file size plus an extra page from either
+ *  anonymous memory or from /dev/zero.  Then map the file text on top of the
+ *  first pages of the anonymous/zero pages.  Otherwise, just map the file
+ *  because there will be NUL bytes provided at the end.
+ *
+ * @param mapinfo a structure holding everything we need to know
+ *        about the mapping.
+ */
+static void
+load_text_file(tmap_info_t * mapinfo)
+{
+#if ! defined(HAVE_MMAP)
+    mapinfo->txt_data = AGALOC(mapinfo->txt_size+1, "file text");
+    if (mapinfo->txt_data == NULL) {
+        mapinfo->txt_errno = ENOMEM;
+        return;
+    }
+
+    {
+        size_t sz = mapinfo->txt_size;
+        char*  pz = mapinfo->txt_data;
+
+        while (sz > 0) {
+            ssize_t rdct = read(mapinfo->txt_fd, pz, sz);
+            if (rdct <= 0) {
+                mapinfo->txt_errno = errno;
+                fprintf(stderr, zFSErrReadFile,
+                        errno, strerror(errno), pzFile);
+                free(mapinfo->txt_data);
+                return;
+            }
+
+            pz += rdct;
+            sz -= rdct;
+        }
+
+        *pz = NUL;
+    }
+
+    mapinfo->txt_errno   = 0;
+
+#else /* HAVE mmap */
+    size_t const pgsz = GETPAGESIZE();
+    void * map_addr   = NULL;
+
+    mapinfo->txt_full_size = (mapinfo->txt_size + pgsz) & ~(pgsz - 1);
+    if (mapinfo->txt_full_size == (mapinfo->txt_size + pgsz)) {
+        /*
+         * The text is a multiple of a page boundary.  We must map an
+         * extra page so the text ends with a NUL.
+         */
+#if defined(MAP_ANONYMOUS)
+        map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE,
+                        MAP_ANONYMOUS|MAP_PRIVATE, AO_INVALID_FD, 0);
+#else
+        mapinfo->txt_zero_fd = open("/dev/zero", O_RDONLY);
+
+        if (mapinfo->txt_zero_fd == AO_INVALID_FD) {
+            mapinfo->txt_errno = errno;
+            return;
+        }
+        map_addr = mmap(NULL, mapinfo->txt_full_size, PROT_READ|PROT_WRITE,
+                        MAP_PRIVATE, mapinfo->txt_zero_fd, 0);
+#endif
+        if (map_addr == MAP_FAILED_PTR) {
+            mapinfo->txt_errno = errno;
+            return;
+        }
+        mapinfo->txt_flags |= MAP_FIXED;
+    }
+
+    mapinfo->txt_data =
+        mmap(map_addr, mapinfo->txt_size, mapinfo->txt_prot,
+             mapinfo->txt_flags, mapinfo->txt_fd, 0);
+
+    if (mapinfo->txt_data == MAP_FAILED_PTR)
+        mapinfo->txt_errno = errno;
+#endif /* HAVE_MMAP */
+}
+
+/**
+ * Make sure all the parameters are correct:  we have a file name that
+ * is a text file that we can read.
+ *
+ * @param fname the text file to map
+ * @param prot  the memory protections requested (read/write/etc.)
+ * @param flags mmap flags
+ * @param mapinfo a structure holding everything we need to know
+ *        about the mapping.
+ */
+static void
+validate_mmap(char const * fname, int prot, int flags, tmap_info_t * mapinfo)
+{
+    memset(mapinfo, 0, sizeof(*mapinfo));
+#if defined(HAVE_MMAP) && ! defined(MAP_ANONYMOUS)
+    mapinfo->txt_zero_fd = AO_INVALID_FD;
+#endif
+    mapinfo->txt_fd      = AO_INVALID_FD;
+    mapinfo->txt_prot    = prot;
+    mapinfo->txt_flags   = flags;
+
+    /*
+     *  Make sure we can stat the regular file.  Save the file size.
+     */
+    {
+        struct stat sb;
+        if (stat(fname, &sb) != 0) {
+            mapinfo->txt_errno = errno;
+            return;
+        }
+
+        if (! S_ISREG(sb.st_mode)) {
+            mapinfo->txt_errno = errno = EINVAL;
+            return;
+        }
+
+        mapinfo->txt_size = sb.st_size;
+    }
+
+    /*
+     *  Map mmap flags and protections into open flags and do the open.
+     */
+    {
+        /*
+         *  See if we will be updating the file.  If we can alter the memory
+         *  and if we share the data and we are *not* copy-on-writing the data,
+         *  then our updates will show in the file, so we must open with
+         *  write access.
+         */
+        int o_flag = FILE_WRITABLE(prot, flags) ? O_RDWR : O_RDONLY;
+
+        /*
+         *  If you're not sharing the file and you are writing to it,
+         *  then don't let anyone else have access to the file.
+         */
+        if (((flags & MAP_SHARED) == 0) && (prot & PROT_WRITE))
+            o_flag |= O_EXCL;
+
+        mapinfo->txt_fd = open(fname, o_flag);
+    }
+
+    if (mapinfo->txt_fd == AO_INVALID_FD)
+        mapinfo->txt_errno = errno;
+}
+
+/**
+ * Close any files opened by the mapping.
+ *
+ * @param mi a structure holding everything we need to know about the map.
+ */
+static void
+close_mmap_files(tmap_info_t * mi)
+{
+    if (mi->txt_fd == AO_INVALID_FD)
+        return;
+
+    close(mi->txt_fd);
+    mi->txt_fd = AO_INVALID_FD;
+
+#if ! defined(MAP_ANONYMOUS)
+    if (mi->txt_zero_fd == AO_INVALID_FD)
+        return;
+
+    close(mi->txt_zero_fd);
+    mi->txt_zero_fd = AO_INVALID_FD;
+#endif
+}
+
+/*=export_func  text_mmap
+ * private:
+ *
+ * what:  map a text file with terminating NUL
+ *
+ * arg:   char const*,  pzFile,  name of the file to map
+ * arg:   int,          prot,    mmap protections (see mmap(2))
+ * arg:   int,          flags,   mmap flags (see mmap(2))
+ * arg:   tmap_info_t*, mapinfo, returned info about the mapping
+ *
+ * ret-type:   void*
+ * ret-desc:   The mmaped data address
+ *
+ * doc:
+ *
+ * This routine will mmap a file into memory ensuring that there is at least
+ * one @file{NUL} character following the file data.  It will return the
+ * address where the file contents have been mapped into memory.  If there is a
+ * problem, then it will return @code{MAP_FAILED} and set @code{errno}
+ * appropriately.
+ *
+ * The named file does not exist, @code{stat(2)} will set @code{errno} as it
+ * will.  If the file is not a regular file, @code{errno} will be
+ * @code{EINVAL}.  At that point, @code{open(2)} is attempted with the access
+ * bits set appropriately for the requested @code{mmap(2)} protections and flag
+ * bits.  On failure, @code{errno} will be set according to the documentation
+ * for @code{open(2)}.  If @code{mmap(2)} fails, @code{errno} will be set as
+ * that routine sets it.  If @code{text_mmap} works to this point, a valid
+ * address will be returned, but there may still be ``issues''.
+ *
+ * If the file size is not an even multiple of the system page size, then
+ * @code{text_map} will return at this point and @code{errno} will be zero.
+ * Otherwise, an anonymous map is attempted.  If not available, then an attempt
+ * is made to @code{mmap(2)} @file{/dev/zero}.  If any of these fail, the
+ * address of the file's data is returned, bug @code{no} @file{NUL} characters
+ * are mapped after the end of the data.
+ *
+ * see: mmap(2), open(2), stat(2)
+ *
+ * err: Any error code issued by mmap(2), open(2), stat(2) is possible.
+ *      Additionally, if the specified file is not a regular file, then
+ *      errno will be set to @code{EINVAL}.
+ *
+ * example:
+ * #include <mylib.h>
+ * tmap_info_t mi;
+ * int no_nul;
+ * void* data = text_mmap("file", PROT_WRITE, MAP_PRIVATE, &mi);
+ * if (data == MAP_FAILED) return;
+ * no_nul = (mi.txt_size == mi.txt_full_size);
+ * << use the data >>
+ * text_munmap(&mi);
+=*/
+void *
+text_mmap(char const * pzFile, int prot, int flags, tmap_info_t * mi)
+{
+    validate_mmap(pzFile, prot, flags, mi);
+    if (mi->txt_errno != 0)
+        return MAP_FAILED_PTR;
+
+    load_text_file(mi);
+
+    if (mi->txt_errno == 0)
+        return mi->txt_data;
+
+    close_mmap_files(mi);
+
+    errno = mi->txt_errno;
+    mi->txt_data = MAP_FAILED_PTR;
+    return mi->txt_data;
+}
+
+
+/*=export_func  text_munmap
+ * private:
+ *
+ * what:  unmap the data mapped in by text_mmap
+ *
+ * arg:   tmap_info_t*, mapinfo, info about the mapping
+ *
+ * ret-type:   int
+ * ret-desc:   -1 or 0.  @code{errno} will have the error code.
+ *
+ * doc:
+ *
+ * This routine will unmap the data mapped in with @code{text_mmap} and close
+ * the associated file descriptors opened by that function.
+ *
+ * see: munmap(2), close(2)
+ *
+ * err: Any error code issued by munmap(2) or close(2) is possible.
+=*/
+int
+text_munmap(tmap_info_t * mi)
+{
+    errno = 0;
+
+#ifdef HAVE_MMAP
+    (void)munmap(mi->txt_data, mi->txt_full_size);
+
+#else  /* don't HAVE_MMAP */
+    /*
+     *  IF the memory is writable *AND* it is not private (copy-on-write)
+     *     *AND* the memory is "sharable" (seen by other processes)
+     *  THEN rewrite the data.  Emulate mmap visibility.
+     */
+    if (   FILE_WRITABLE(mi->txt_prot, mi->txt_flags)
+        && (lseek(mi->txt_fd, 0, SEEK_SET) >= 0) ) {
+        write(mi->txt_fd, mi->txt_data, mi->txt_size);
+    }
+
+    free(mi->txt_data);
+#endif /* HAVE_MMAP */
+
+    mi->txt_errno = errno;
+    close_mmap_files(mi);
+
+    return mi->txt_errno;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/text_mmap.c */
diff --git a/libopts/time.c b/libopts/time.c
new file mode 100644 (file)
index 0000000..656c78d
--- /dev/null
@@ -0,0 +1,137 @@
+
+/**
+ * \file time.c
+ *
+ *  Time-stamp:      "2011-03-06 11:52:23 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*=export_func  optionTimeVal
+ * private:
+ *
+ * what:  process an option with a time duration.
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Decipher a time duration value.
+=*/
+void
+optionTimeVal(tOptions * pOpts, tOptDesc * pOD)
+{
+    time_t val;
+
+    if ((pOD->fOptState & OPTST_RESET) != 0)
+        return;
+
+    val = parse_duration(pOD->optArg.argString);
+    if (val == BAD_TIME) {
+        fprintf(stderr, zNotDuration, pOpts->pzProgName, pOD->optArg.argString);
+        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
+            (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+    }
+
+    if (pOD->fOptState & OPTST_ALLOC_ARG) {
+        AGFREE(pOD->optArg.argString);
+        pOD->fOptState &= ~OPTST_ALLOC_ARG;
+    }
+
+    pOD->optArg.argInt = val;
+}
+
+/*=export_func  optionTimeDate
+ * private:
+ *
+ * what:  process an option with a time and date.
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  Decipher a time and date value.
+=*/
+void
+optionTimeDate(tOptions * pOpts, tOptDesc * pOD)
+{
+#if defined(HAVE_GETDATE_R) && defined(HAVE_PUTENV)
+    if ((! HAS_pzPkgDataDir(pOpts)) || (pOpts->pzPkgDataDir == NULL))
+        goto default_action;
+
+    /*
+     *  Export the DATEMSK environment variable.  getdate_r() uses it to
+     *  find the file with the strptime formats.  If we cannot find the file
+     *  we need ($PKGDATADIR/datemsk), then fall back to just a time duration.
+     */
+    {
+        static char * envptr = NULL;
+
+        if (envptr == NULL) {
+            static char const fmt[] = "DATEMSK=%s/datemsk";
+            envptr = AGALOC(sizeof(fmt) + strlen(pOpts->pzPkgDataDir), fmt);
+            sprintf(envptr, fmt, pOpts->pzPkgDataDir);
+
+            putenv(envptr);
+        }
+
+        if (access(envptr+8, R_OK) != 0)
+            goto default_action;
+    }
+
+    /*
+     *  Convert the date to a time since the epoch and stash it in a long int.
+     */
+    {
+        struct tm stm;
+        time_t tm;
+
+        if (getdate_r(pOD->optArg.argString, &stm) != 0) {
+            fprintf(stderr, zNotDate, pOpts->pzProgName,
+                    pOD->optArg.argString);
+            if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
+                (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+            return;
+        }
+
+        tm = mktime(&stm);
+
+        if (pOD->fOptState & OPTST_ALLOC_ARG) {
+            AGFREE(pOD->optArg.argString);
+            pOD->fOptState &= ~OPTST_ALLOC_ARG;
+        }
+
+        pOD->optArg.argInt = tm;
+    }
+    return;
+
+default_action:
+
+#endif
+    optionTimeVal(pOpts, pOD);
+    if (pOD->optArg.argInt != BAD_TIME)
+        pOD->optArg.argInt += (unsigned long)time(NULL);
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/time.c */
diff --git a/libopts/tokenize.c b/libopts/tokenize.c
new file mode 100644 (file)
index 0000000..4ca1245
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  This file defines the string_tokenize interface
+ * Time-stamp:      "2010-07-17 10:40:26 bkorb"
+ *
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#define cc_t   const unsigned char
+#define ch_t   unsigned char
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+copy_cooked(ch_t** ppDest, char const ** ppSrc);
+
+static void
+copy_raw(ch_t** ppDest, char const ** ppSrc);
+
+static token_list_t *
+alloc_token_list(char const * str);
+/* = = = END-STATIC-FORWARD = = = */
+
+static void
+copy_cooked(ch_t** ppDest, char const ** ppSrc)
+{
+    ch_t* pDest = (ch_t*)*ppDest;
+    const ch_t* pSrc  = (const ch_t*)(*ppSrc + 1);
+
+    for (;;) {
+        ch_t ch = *(pSrc++);
+        switch (ch) {
+        case NUL:   *ppSrc = NULL; return;
+        case '"':   goto done;
+        case '\\':
+            pSrc += ao_string_cook_escape_char((char*)pSrc, (char*)&ch, 0x7F);
+            if (ch == 0x7F)
+                break;
+            /* FALLTHROUGH */
+
+        default:
+            *(pDest++) = ch;
+        }
+    }
+
+ done:
+    *ppDest = (ch_t*)pDest; /* next spot for storing character */
+    *ppSrc  = (char const *)pSrc;  /* char following closing quote    */
+}
+
+
+static void
+copy_raw(ch_t** ppDest, char const ** ppSrc)
+{
+    ch_t* pDest = *ppDest;
+    cc_t* pSrc  = (cc_t*) (*ppSrc + 1);
+
+    for (;;) {
+        ch_t ch = *(pSrc++);
+        switch (ch) {
+        case NUL:   *ppSrc = NULL; return;
+        case '\'':  goto done;
+        case '\\':
+            /*
+             *  *Four* escapes are handled:  newline removal, escape char
+             *  quoting and apostrophe quoting
+             */
+            switch (*pSrc) {
+            case NUL:   *ppSrc = NULL; return;
+            case '\r':
+                if (*(++pSrc) == '\n')
+                    ++pSrc;
+                continue;
+
+            case '\n':
+                ++pSrc;
+                continue;
+
+            case '\'':
+                ch = '\'';
+                /* FALLTHROUGH */
+
+            case '\\':
+                ++pSrc;
+                break;
+            }
+            /* FALLTHROUGH */
+
+        default:
+            *(pDest++) = ch;
+        }
+    }
+
+ done:
+    *ppDest = pDest; /* next spot for storing character */
+    *ppSrc  = (char const *) pSrc;  /* char following closing quote    */
+}
+
+static token_list_t *
+alloc_token_list(char const * str)
+{
+    token_list_t * res;
+
+    int max_token_ct = 2; /* allow for trailing NULL pointer & NUL on string */
+
+    if (str == NULL) goto enoent_res;
+
+    /*
+     *  Trim leading white space.  Use "ENOENT" and a NULL return to indicate
+     *  an empty string was passed.
+     */
+    while (IS_WHITESPACE_CHAR(*str))  str++;
+    if (*str == NUL)  goto enoent_res;
+
+    /*
+     *  Take an approximate count of tokens.  If no quoted strings are used,
+     *  it will be accurate.  If quoted strings are used, it will be a little
+     *  high and we'll squander the space for a few extra pointers.
+     */
+    {
+        cc_t* pz = (cc_t*)str;
+
+        do {
+            max_token_ct++;
+            while (! IS_WHITESPACE_CHAR(*++pz))
+                if (*pz == NUL) goto found_nul;
+            while (IS_WHITESPACE_CHAR(*pz))  pz++;
+        } while (*pz != NUL);
+
+    found_nul:
+        res = malloc(sizeof(*res) + (pz - (cc_t*)str)
+                     + (max_token_ct * sizeof(ch_t*)));
+    }
+
+    if (res == NULL)
+        errno = ENOMEM;
+    else res->tkn_list[0] = (ch_t*)(res->tkn_list + (max_token_ct - 1));
+
+    return res;
+
+    enoent_res:
+
+    errno = ENOENT;
+    return NULL;
+}
+
+/*=export_func ao_string_tokenize
+ *
+ * what: tokenize an input string
+ *
+ * arg:  + char const* + string + string to be tokenized +
+ *
+ * ret_type:  token_list_t*
+ * ret_desc:  pointer to a structure that lists each token
+ *
+ * doc:
+ *
+ * This function will convert one input string into a list of strings.
+ * The list of strings is derived by separating the input based on
+ * white space separation.  However, if the input contains either single
+ * or double quote characters, then the text after that character up to
+ * a matching quote will become the string in the list.
+ *
+ *  The returned pointer should be deallocated with @code{free(3C)} when
+ *  are done using the data.  The data are placed in a single block of
+ *  allocated memory.  Do not deallocate individual token/strings.
+ *
+ *  The structure pointed to will contain at least these two fields:
+ *  @table @samp
+ *  @item tkn_ct
+ *  The number of tokens found in the input string.
+ *  @item tok_list
+ *  An array of @code{tkn_ct + 1} pointers to substring tokens, with
+ *  the last pointer set to NULL.
+ *  @end table
+ *
+ * There are two types of quoted strings: single quoted (@code{'}) and
+ * double quoted (@code{"}).  Singly quoted strings are fairly raw in that
+ * escape characters (@code{\\}) are simply another character, except when
+ * preceding the following characters:
+ * @example
+ * @code{\\}  double backslashes reduce to one
+ * @code{'}   incorporates the single quote into the string
+ * @code{\n}  suppresses both the backslash and newline character
+ * @end example
+ *
+ * Double quote strings are formed according to the rules of string
+ * constants in ANSI-C programs.
+ *
+ * example:
+ * @example
+ *    #include <stdlib.h>
+ *    int ix;
+ *    token_list_t* ptl = ao_string_tokenize(some_string)
+ *    for (ix = 0; ix < ptl->tkn_ct; ix++)
+ *       do_something_with_tkn(ptl->tkn_list[ix]);
+ *    free(ptl);
+ * @end example
+ * Note that everything is freed with the one call to @code{free(3C)}.
+ *
+ * err:
+ *  NULL is returned and @code{errno} will be set to indicate the problem:
+ *  @itemize @bullet
+ *  @item
+ *  @code{EINVAL} - There was an unterminated quoted string.
+ *  @item
+ *  @code{ENOENT} - The input string was empty.
+ *  @item
+ *  @code{ENOMEM} - There is not enough memory.
+ *  @end itemize
+=*/
+token_list_t*
+ao_string_tokenize(char const* str)
+{
+    token_list_t* res = alloc_token_list(str);
+    ch_t* pzDest;
+
+    /*
+     *  Now copy each token into the output buffer.
+     */
+    if (res == NULL)
+        return res;
+
+    pzDest = (ch_t*)(res->tkn_list[0]);
+    res->tkn_ct  = 0;
+
+    do  {
+        res->tkn_list[ res->tkn_ct++ ] = pzDest;
+        for (;;) {
+            int ch = (ch_t)*str;
+            if (IS_WHITESPACE_CHAR(ch)) {
+            found_white_space:
+                while (IS_WHITESPACE_CHAR(*++str))  ;
+                break;
+            }
+
+            switch (ch) {
+            case '"':
+                copy_cooked(&pzDest, &str);
+                if (str == NULL) {
+                    free(res);
+                    errno = EINVAL;
+                    return NULL;
+                }
+                if (IS_WHITESPACE_CHAR(*str))
+                    goto found_white_space;
+                break;
+
+            case '\'':
+                copy_raw(&pzDest, &str);
+                if (str == NULL) {
+                    free(res);
+                    errno = EINVAL;
+                    return NULL;
+                }
+                if (IS_WHITESPACE_CHAR(*str))
+                    goto found_white_space;
+                break;
+
+            case NUL:
+                goto copy_done;
+
+            default:
+                str++;
+                *(pzDest++) = ch;
+            }
+        } copy_done:;
+
+        /*
+         * NUL terminate the last token and see if we have any more tokens.
+         */
+        *(pzDest++) = NUL;
+    } while (*str != NUL);
+
+    res->tkn_list[ res->tkn_ct ] = NULL;
+
+    return res;
+}
+
+#ifdef TEST
+#include <stdio.h>
+#include <string.h>
+
+int
+main(int argc, char** argv)
+{
+    if (argc == 1) {
+        printf("USAGE:  %s arg [ ... ]\n", *argv);
+        return 1;
+    }
+    while (--argc > 0) {
+        char* arg = *(++argv);
+        token_list_t* p = ao_string_tokenize(arg);
+        if (p == NULL) {
+            printf("Parsing string ``%s'' failed:\n\terrno %d (%s)\n",
+                   arg, errno, strerror(errno));
+        } else {
+            int ix = 0;
+            printf("Parsed string ``%s''\ninto %d tokens:\n", arg, p->tkn_ct);
+            do {
+                printf(" %3d:  ``%s''\n", ix+1, p->tkn_list[ix]);
+            } while (++ix < p->tkn_ct);
+            free(p);
+        }
+    }
+    return 0;
+}
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/tokenize.c */
diff --git a/libopts/usage.c b/libopts/usage.c
new file mode 100644 (file)
index 0000000..e2751cb
--- /dev/null
@@ -0,0 +1,1055 @@
+
+/*
+ * \file usage.c
+ *
+ * Time-stamp:      "2011-11-22 11:41:18 bkorb"
+ *
+ *  This module implements the default usage procedure for
+ *  Automated Options.  It may be overridden, of course.
+ *
+ *  Sort options:
+    --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
+    --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
+    --spac=2 --input=usage.c
+ */
+
+/*
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+#define OPTPROC_L_N_S  (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
+
+/* = = = START-STATIC-FORWARD = = = */
+static inline ag_bool
+do_gnu_usage(tOptions * pOpts);
+
+static inline ag_bool
+skip_misuse_usage(tOptions * pOpts);
+
+static void
+print_usage_details(tOptions * opts, int exit_code);
+
+static void
+prt_conflicts(tOptions * pOptions, tOptDesc * pOD);
+
+static void
+prt_one_vendor(tOptions * pOptions, tOptDesc * pOD,
+               arg_types_t * pAT, char const * usefmt);
+
+static void
+prt_vendor_opts(tOptions * pOpts, arg_types_t * pAT, char const * pOptTitle);
+
+static void
+prt_extd_usage(tOptions * pOpts, tOptDesc * pOD,
+               arg_types_t * pAT, char const * pOptTitle);
+
+static void
+prt_ini_list(char const * const * papz, ag_bool * pInitIntro,
+             char const * pzRc, char const * pzPN);
+
+static void
+prt_preamble(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT);
+
+static void
+prt_one_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT);
+
+static void
+prt_opt_usage(tOptions * pOpts, int ex_code, char const * pOptTitle);
+
+static void
+prt_prog_detail(tOptions* pOptions);
+
+static int
+setGnuOptFmts(tOptions* pOpts, tCC** ppT);
+
+static int
+setStdOptFmts(tOptions* pOpts, tCC** ppT);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*
+ *  NB: no entry may be a prefix of another entry
+ */
+#define AOFLAG_TABLE                            \
+    _aof_(gnu,             OPTPROC_GNUUSAGE )   \
+    _aof_(autoopts,        ~OPTPROC_GNUUSAGE)   \
+    _aof_(no_misuse_usage, OPTPROC_MISUSE   )   \
+    _aof_(misuse_usage,    ~OPTPROC_MISUSE  )
+
+LOCAL void
+set_usage_flags(tOptions * opts, char const * flg_txt)
+{
+    typedef struct {
+        size_t          fnm_len;
+        uint32_t        fnm_mask;
+        char const *    fnm_name;
+    } ao_flag_names_t;
+
+#   define _aof_(_n, _f)   AOUF_ ## _n ## _ID,
+    typedef enum { AOFLAG_TABLE AOUF_COUNT } ao_flag_id_t;
+#   undef  _aof_
+
+#   define _aof_(_n, _f)   AOUF_ ## _n = (1 << AOUF_ ## _n ## _ID),
+    typedef enum { AOFLAG_TABLE } ao_flags_t;
+#   undef  _aof_
+
+#   define _aof_(_n, _f)   { sizeof(#_n)-1, _f, #_n },
+    static ao_flag_names_t const fn_table[AOUF_COUNT] = {
+        AOFLAG_TABLE
+    };
+#   undef  _aof_
+
+    ao_flags_t flg = 0;
+
+    if (flg_txt == NULL) {
+        flg_txt = getenv("AUTOOPTS_USAGE");
+        if (flg_txt == NULL) return;
+    }
+
+    while (IS_WHITESPACE_CHAR(*flg_txt))  flg_txt++;
+    if (*flg_txt == NUL)
+        return;
+
+    for (;;) {
+        int ix = 0;
+        ao_flag_names_t const * fnt = fn_table;
+
+        for (;;) {
+            if (strneqvcmp(flg_txt, fnt->fnm_name, fnt->fnm_len) == 0)
+                break;
+            if (++ix >= AOUF_COUNT)
+                return;
+            fnt++;
+        }
+
+        /*
+         *  Make sure we have a full match.  Look for whitespace,
+         *  a comma, or a NUL byte.
+         */
+        if (! IS_END_LIST_ENTRY_CHAR(flg_txt[fnt->fnm_len]))
+            return;
+
+        flg |= 1 << ix;
+        flg_txt  += fnt->fnm_len;
+        while (IS_WHITESPACE_CHAR(*flg_txt))  flg_txt++;
+
+        if (*flg_txt == NUL)
+            break;
+
+        if (*flg_txt == ',') {
+            /*
+             *  skip the comma and following white space
+             */
+            while (IS_WHITESPACE_CHAR(*++flg_txt))  ;
+            if (*flg_txt == NUL)
+                break;
+        }
+    }
+
+    {
+        ao_flag_names_t const * fnm = fn_table;
+
+        while (flg != 0) {
+            if ((flg & 1) != 0) {
+                if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0)
+                     opts->fOptSet &= fnm->fnm_mask;
+                else opts->fOptSet |= fnm->fnm_mask;
+            }
+            flg >>= 1;
+            fnm++;
+        }
+    }
+}
+
+/*
+ *  Figure out if we should try to format usage text sort-of like
+ *  the way many GNU programs do.
+ */
+static inline ag_bool
+do_gnu_usage(tOptions * pOpts)
+{
+    return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? AG_TRUE : AG_FALSE;
+}
+
+/*
+ *  Figure out if we should try to format usage text sort-of like
+ *  the way many GNU programs do.
+ */
+static inline ag_bool
+skip_misuse_usage(tOptions * pOpts)
+{
+    return (pOpts->fOptSet & OPTPROC_MISUSE) ? AG_TRUE : AG_FALSE;
+}
+
+
+/*=export_func  optionOnlyUsage
+ *
+ * what:  Print usage text for just the options
+ * arg:   + tOptions*   + pOpts    + program options descriptor +
+ * arg:   + int         + ex_code  + exit code for calling exit(3) +
+ *
+ * doc:
+ *  This routine will print only the usage for each option.
+ *  This function may be used when the emitted usage must incorporate
+ *  information not available to AutoOpts.
+=*/
+void
+optionOnlyUsage(tOptions * pOpts, int ex_code)
+{
+    char const * pOptTitle = NULL;
+
+    set_usage_flags(pOpts, NULL);
+    if ((ex_code != EXIT_SUCCESS) &&
+        skip_misuse_usage(pOpts))
+        return;
+
+    /*
+     *  Determine which header and which option formatting strings to use
+     */
+    if (do_gnu_usage(pOpts))
+        (void)setGnuOptFmts(pOpts, &pOptTitle);
+    else
+        (void)setStdOptFmts(pOpts, &pOptTitle);
+
+    prt_opt_usage(pOpts, ex_code, pOptTitle);
+
+    fflush(option_usage_fp);
+    if (ferror(option_usage_fp) != 0) {
+        fputs(zOutputFail, stderr);
+        exit(EXIT_FAILURE);
+    }
+}
+
+static void
+print_usage_details(tOptions * opts, int exit_code)
+{
+    {
+        char const * pOptTitle = NULL;
+
+        /*
+         *  Determine which header and which option formatting strings to use
+         */
+        if (do_gnu_usage(opts)) {
+            int flen = setGnuOptFmts(opts, &pOptTitle);
+            sprintf(zOptFmtLine, zFmtFmt, flen);
+            fputc('\n', option_usage_fp);
+        }
+        else {
+            int flen = setStdOptFmts(opts, &pOptTitle);
+            sprintf(zOptFmtLine, zFmtFmt, flen);
+
+            /*
+             *  When we exit with EXIT_SUCCESS and the first option is a doc
+             *  option, we do *NOT* want to emit the column headers.
+             *  Otherwise, we do.
+             */
+            if (  (exit_code != EXIT_SUCCESS)
+               || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
+
+                fputs(pOptTitle, option_usage_fp);
+        }
+
+        prt_opt_usage(opts, exit_code, pOptTitle);
+    }
+
+    /*
+     *  Describe the mechanics of denoting the options
+     */
+    switch (opts->fOptSet & OPTPROC_L_N_S) {
+    case OPTPROC_L_N_S:     fputs(zFlagOkay, option_usage_fp); break;
+    case OPTPROC_SHORTOPT:  break;
+    case OPTPROC_LONGOPT:   fputs(zNoFlags,  option_usage_fp); break;
+    case 0:                 fputs(zOptsOnly, option_usage_fp); break;
+    }
+
+    if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0)
+        fputs(zNumberOpt, option_usage_fp);
+
+    if ((opts->fOptSet & OPTPROC_REORDER) != 0)
+        fputs(zReorder, option_usage_fp);
+
+    if (opts->pzExplain != NULL)
+        fputs(opts->pzExplain, option_usage_fp);
+
+    /*
+     *  IF the user is asking for help (thus exiting with SUCCESS),
+     *  THEN see what additional information we can provide.
+     */
+    if (exit_code == EXIT_SUCCESS)
+        prt_prog_detail(opts);
+
+    /*
+     * Give bug notification preference to the packager information
+     */
+    if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL))
+        fputs(opts->pzPackager, option_usage_fp);
+
+    else if (opts->pzBugAddr != NULL)
+        fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr);
+
+    fflush(option_usage_fp);
+
+    if (ferror(option_usage_fp) != 0) {
+        fputs(zOutputFail, stderr);
+        exit(EXIT_FAILURE);
+    }
+}
+
+
+/*=export_func  optionUsage
+ * private:
+ *
+ * what:  Print usage text
+ * arg:   + tOptions* + pOptions + program options descriptor +
+ * arg:   + int       + exitCode + exit code for calling exit(3) +
+ *
+ * doc:
+ *  This routine will print usage in both GNU-standard and AutoOpts-expanded
+ *  formats.  The descriptor specifies the default, but AUTOOPTS_USAGE will
+ *  over-ride this, providing the value of it is set to either "gnu" or
+ *  "autoopts".  This routine will @strong{not} return.
+ *
+ *  If "exitCode" is "EX_USAGE" (normally 64), then output will to to stdout
+ *  and the actual exit code will be "EXIT_SUCCESS".
+=*/
+void
+optionUsage(tOptions * pOptions, int usage_exit_code)
+{
+    int exit_code =
+        (usage_exit_code == EX_USAGE) ? EXIT_SUCCESS : usage_exit_code;
+
+    displayEnum = AG_FALSE;
+
+    /*
+     *  Paged usage will preset option_usage_fp to an output file.
+     *  If it hasn't already been set, then set it to standard output
+     *  on successful exit (help was requested), otherwise error out.
+     *
+     *  Test the version before obtaining pzFullUsage or pzShortUsage.
+     *  These fields do not exist before revision 30.
+     */
+    {
+        char const * pz;
+
+        if (exit_code == EXIT_SUCCESS) {
+            pz = (pOptions->structVersion >= 30 * 4096)
+                ? pOptions->pzFullUsage : NULL;
+
+            if (option_usage_fp == NULL)
+                option_usage_fp = stdout;
+        } else {
+            pz = (pOptions->structVersion >= 30 * 4096)
+                ? pOptions->pzShortUsage : NULL;
+
+            if (option_usage_fp == NULL)
+                option_usage_fp = stderr;
+        }
+
+        if (pz != NULL) {
+            fputs(pz, option_usage_fp);
+            exit(exit_code);
+        }
+    }
+
+    fprintf(option_usage_fp, pOptions->pzUsageTitle, pOptions->pzProgName);
+    set_usage_flags(pOptions, NULL);
+
+    if ((exit_code == EXIT_SUCCESS) ||
+        (! skip_misuse_usage(pOptions)))
+
+        print_usage_details(pOptions, usage_exit_code);
+
+    exit(exit_code);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   PER OPTION TYPE USAGE INFORMATION
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * print option conflicts.
+ *
+ * @param pOptions the program option descriptor
+ * @param pOD      the option descriptor
+ * @param pAT      names of the option argument types
+ */
+static void
+prt_conflicts(tOptions * pOptions, tOptDesc * pOD)
+{
+
+    fputs(zTabHyp, option_usage_fp);
+
+    /*
+     *  REQUIRED:
+     */
+    if (pOD->pOptMust != NULL) {
+        const int* pOptNo = pOD->pOptMust;
+
+        fputs(zReqThese, option_usage_fp);
+        for (;;) {
+            fprintf(option_usage_fp, zTabout,
+                    pOptions->pOptDesc[*pOptNo].pz_Name);
+            if (*++pOptNo == NO_EQUIVALENT)
+                break;
+        }
+
+        if (pOD->pOptCant != NULL)
+            fputs(zTabHypAnd, option_usage_fp);
+    }
+
+    /*
+     *  CONFLICTS:
+     */
+    if (pOD->pOptCant != NULL) {
+        const int* pOptNo = pOD->pOptCant;
+
+        fputs(zProhib, option_usage_fp);
+        for (;;) {
+            fprintf(option_usage_fp, zTabout,
+                    pOptions->pOptDesc[*pOptNo].pz_Name);
+            if (*++pOptNo == NO_EQUIVALENT)
+                break;
+        }
+    }
+}
+
+/**
+ *  Print the usage information for a single vendor option.
+ *
+ * @param pOpts     the program option descriptor
+ * @param pOD       the option descriptor
+ * @param pAT       names of the option argument types
+ */
+static void
+prt_one_vendor(tOptions * pOptions, tOptDesc * pOD,
+               arg_types_t * pAT, char const * usefmt)
+{
+    prt_preamble(pOptions, pOD, pAT);
+
+    {
+        char z[ 80 ];
+        char const *  pzArgType;
+
+        /*
+         *  Determine the argument type string first on its usage, then,
+         *  when the option argument is required, base the type string on the
+         *  argument type.
+         */
+        if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
+            pzArgType = pAT->pzOpt;
+
+        } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_NONE:        pzArgType = pAT->pzNo;   break;
+        case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey;  break;
+        case OPARG_TYPE_FILE:        pzArgType = pAT->pzFile; break;
+        case OPARG_TYPE_MEMBERSHIP:  pzArgType = pAT->pzKeyL; break;
+        case OPARG_TYPE_BOOLEAN:     pzArgType = pAT->pzBool; break;
+        case OPARG_TYPE_NUMERIC:     pzArgType = pAT->pzNum;  break;
+        case OPARG_TYPE_HIERARCHY:   pzArgType = pAT->pzNest; break;
+        case OPARG_TYPE_STRING:      pzArgType = pAT->pzStr;  break;
+        case OPARG_TYPE_TIME:        pzArgType = pAT->pzTime; break;
+        default:                     goto bogus_desc;
+        }
+
+        while (IS_WHITESPACE_CHAR(*pzArgType))  pzArgType++;
+        if (*pzArgType == NUL)
+            snprintf(z, sizeof(z), "%s", pOD->pz_Name);
+        else
+            snprintf(z, sizeof(z), "%s=%s", pOD->pz_Name, pzArgType);
+        fprintf(option_usage_fp, usefmt, z, pOD->pzText);
+
+        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_ENUMERATION:
+        case OPARG_TYPE_MEMBERSHIP:
+            displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum;
+        }
+    }
+
+    return;
+
+bogus_desc:
+    fprintf(stderr, zInvalOptDesc, pOD->pz_Name);
+    exit(EX_SOFTWARE);
+}
+
+/**
+ * Print the long options processed with "-W".  These options will be the
+ * ones that do *not* have flag characters.
+ *
+ * @param pOptions the program option descriptor
+ * @param pOD      the option descriptor
+ * @param pAT      names of the option argument types
+ */
+static void
+prt_vendor_opts(tOptions * pOpts, arg_types_t * pAT, char const * pOptTitle)
+{
+    static unsigned int const not_vended_mask =
+        OPTST_NO_USAGE_MASK | OPTST_DOCUMENT;
+
+    static char const vfmtfmt[] = "%%-%us %%s\n";
+    char vfmt[sizeof(vfmtfmt)];
+
+    /*
+     *  Only handle client specified options.  The "vendor option" follows
+     *  "presetOptCt", so we won't loop/recurse indefinitely.
+     */
+    int          ct     = pOpts->presetOptCt;
+    tOptDesc *   pOD    = pOpts->pOptDesc;
+    size_t       nmlen  = 0;
+
+    fprintf(option_usage_fp, zTabout, zVendOptsAre);
+
+    do  {
+        size_t l;
+        if (  ((pOD->fOptState & not_vended_mask) != 0)
+           || IS_GRAPHIC_CHAR(pOD->optValue))
+            continue;
+
+        l = strlen(pOD->pz_Name);
+        if (l > nmlen)  nmlen = l;
+    } while (pOD++, (--ct > 0));
+
+    sprintf(vfmt, vfmtfmt, (unsigned int)nmlen + 4);
+    ct     = pOpts->presetOptCt;
+    pOD    = pOpts->pOptDesc;
+
+    do  {
+        if (  ((pOD->fOptState & not_vended_mask) != 0)
+           || IS_GRAPHIC_CHAR(pOD->optValue))
+            continue;
+
+        prt_one_vendor(pOpts, pOD, &argTypes, vfmt);
+        prt_extd_usage(pOpts, pOD, &argTypes, pOptTitle);
+
+    } while (pOD++, (--ct > 0));
+}
+
+/**
+ * Print extended usage.  Usage/help was requested.
+ *
+ * @param pOptions the program option descriptor
+ * @param pOD      the option descriptor
+ * @param pAT      names of the option argument types
+ */
+static void
+prt_extd_usage(tOptions * pOpts, tOptDesc * pOD,
+               arg_types_t * pAT, char const * pOptTitle)
+{
+    if (  ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
+       && (pOD->optActualValue == VENDOR_OPTION_VALUE)) {
+        prt_vendor_opts(pOpts, pAT, pOptTitle);
+        return;
+    }
+
+    /*
+     *  IF there are option conflicts or dependencies,
+     *  THEN print them here.
+     */
+    if (  (pOD->pOptMust != NULL)
+       || (pOD->pOptCant != NULL) )
+        prt_conflicts(pOpts, pOD);
+
+    /*
+     *  IF there is a disablement string
+     *  THEN print the disablement info
+     */
+    if (pOD->pz_DisableName != NULL )
+        fprintf(option_usage_fp, zDis, pOD->pz_DisableName);
+
+    /*
+     *  Check for argument types that have callbacks with magical properties
+     */
+    switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+    case OPARG_TYPE_NUMERIC:
+        /*
+         *  IF the numeric option has a special callback,
+         *  THEN call it, requesting the range or other special info
+         */
+        if (  (pOD->pOptProc != NULL)
+           && (pOD->pOptProc != optionNumericVal) ) {
+            (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
+        }
+        break;
+
+    case OPARG_TYPE_FILE:
+        (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
+        break;
+    }
+
+    /*
+     *  IF the option defaults to being enabled,
+     *  THEN print that out
+     */
+    if (pOD->fOptState & OPTST_INITENABLED)
+        fputs(zEnab, option_usage_fp);
+
+    /*
+     *  IF  the option is in an equivalence class
+     *        AND not the designated lead
+     *  THEN print equivalence and leave it at that.
+     */
+    if (  (pOD->optEquivIndex != NO_EQUIVALENT)
+       && (pOD->optEquivIndex != pOD->optActualIndex )  )  {
+        fprintf(option_usage_fp, zAlt,
+                 pOpts->pOptDesc[ pOD->optEquivIndex ].pz_Name);
+        return;
+    }
+
+    /*
+     *  IF this particular option can NOT be preset
+     *    AND some form of presetting IS allowed,
+     *    AND it is not an auto-managed option (e.g. --help, et al.)
+     *  THEN advise that this option may not be preset.
+     */
+    if (  ((pOD->fOptState & OPTST_NO_INIT) != 0)
+       && (  (pOpts->papzHomeList != NULL)
+          || (pOpts->pzPROGNAME != NULL)
+          )
+       && (pOD->optIndex < pOpts->presetOptCt)
+       )
+
+        fputs(zNoPreset, option_usage_fp);
+
+    /*
+     *  Print the appearance requirements.
+     */
+    if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
+        fputs(zMembers, option_usage_fp);
+
+    else switch (pOD->optMinCt) {
+    case 1:
+    case 0:
+        switch (pOD->optMaxCt) {
+        case 0:       fputs(zPreset, option_usage_fp); break;
+        case NOLIMIT: fputs(zNoLim, option_usage_fp);  break;
+        case 1:       break;
+            /*
+             * IF the max is more than one but limited, print "UP TO" message
+             */
+        default:      fprintf(option_usage_fp, zUpTo, pOD->optMaxCt);  break;
+        }
+        break;
+
+    default:
+        /*
+         *  More than one is required.  Print the range.
+         */
+        fprintf(option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt);
+    }
+
+    if (  NAMED_OPTS(pOpts)
+       && (pOpts->specOptIdx.default_opt == pOD->optIndex))
+        fputs(zDefaultOpt, option_usage_fp);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   Figure out where all the initialization files might live.
+ *   This requires translating some environment variables and
+ *   testing to see if a name is a directory or a file.  It's
+ *   squishy, but important to tell users how to find these files.
+ */
+static void
+prt_ini_list(char const * const * papz, ag_bool * pInitIntro,
+             char const * pzRc, char const * pzPN)
+{
+    char zPath[AG_PATH_MAX+1];
+
+    if (papz == NULL)
+        return;
+
+    fputs(zPresetIntro, option_usage_fp);
+    *pInitIntro = AG_FALSE;
+
+    for (;;) {
+        char const * pzPath = *(papz++);
+        char const * pzReal = zPath;
+
+        if (pzPath == NULL)
+            break;
+
+        /*
+         * Ignore any invalid paths
+         */
+        if (! optionMakePath(zPath, (int)sizeof(zPath), pzPath, pzPN))
+            pzReal = pzPath;
+
+        /*
+         * Expand paths that are relative to the executable or installation
+         * directories.  Leave alone paths that use environment variables.
+         */
+        else if ((*pzPath == '$')
+                 && ((pzPath[1] == '$') || (pzPath[1] == '@')))
+            pzPath = pzReal;
+
+        /*
+         *  Print the name of the "homerc" file.  If the "rcfile" name is
+         *  not empty, we may or may not print that, too...
+         */
+        fprintf(option_usage_fp, zPathFmt, pzPath);
+        if (*pzRc != NUL) {
+            struct stat sb;
+
+            /*
+             *  IF the "homerc" file is a directory,
+             *  then append the "rcfile" name.
+             */
+            if ((stat(pzReal, &sb) == 0) && S_ISDIR(sb.st_mode)) {
+                fputc(DIRCH, option_usage_fp);
+                fputs(pzRc,  option_usage_fp);
+            }
+        }
+
+        fputc('\n', option_usage_fp);
+    }
+}
+
+
+static void
+prt_preamble(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT)
+{
+    /*
+     *  Flag prefix: IF no flags at all, then omit it.  If not printable
+     *  (not allowed for this option), then blank, else print it.
+     *  Follow it with a comma if we are doing GNU usage and long
+     *  opts are to be printed too.
+     */
+    if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0)
+        fputs(pAT->pzSpc, option_usage_fp);
+
+    else if (! IS_GRAPHIC_CHAR(pOD->optValue)) {
+        if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+           == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+            fputc(' ', option_usage_fp);
+        fputs(pAT->pzNoF, option_usage_fp);
+
+    } else {
+        fprintf(option_usage_fp, "   -%c", pOD->optValue);
+        if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+           == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+            fputs(", ", option_usage_fp);
+    }
+}
+
+/**
+ *  Print the usage information for a single option.
+ *
+ * @param pOpts     the program option descriptor
+ * @param pOD       the option descriptor
+ * @param pAT       names of the option argument types
+ */
+static void
+prt_one_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT)
+{
+    prt_preamble(pOptions, pOD, pAT);
+
+    {
+        char z[ 80 ];
+        char const *  pzArgType;
+
+        /*
+         *  Determine the argument type string first on its usage, then,
+         *  when the option argument is required, base the type string on the
+         *  argument type.
+         */
+        if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
+            pzArgType = pAT->pzOpt;
+
+        } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_NONE:        pzArgType = pAT->pzNo;   break;
+        case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey;  break;
+        case OPARG_TYPE_FILE:        pzArgType = pAT->pzFile; break;
+        case OPARG_TYPE_MEMBERSHIP:  pzArgType = pAT->pzKeyL; break;
+        case OPARG_TYPE_BOOLEAN:     pzArgType = pAT->pzBool; break;
+        case OPARG_TYPE_NUMERIC:     pzArgType = pAT->pzNum;  break;
+        case OPARG_TYPE_HIERARCHY:   pzArgType = pAT->pzNest; break;
+        case OPARG_TYPE_STRING:      pzArgType = pAT->pzStr;  break;
+        case OPARG_TYPE_TIME:        pzArgType = pAT->pzTime; break;
+        default:                     goto bogus_desc;
+        }
+
+        snprintf(z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name,
+                 (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt);
+
+        fprintf(option_usage_fp, zOptFmtLine, z, pOD->pzText);
+
+        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+        case OPARG_TYPE_ENUMERATION:
+        case OPARG_TYPE_MEMBERSHIP:
+            displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum;
+        }
+    }
+
+    return;
+
+bogus_desc:
+    fprintf(stderr, zInvalOptDesc, pOD->pz_Name);
+    exit(EX_SOFTWARE);
+}
+
+/*
+ *  Print out the usage information for just the options.
+ */
+static void
+prt_opt_usage(tOptions * pOpts, int ex_code, char const * pOptTitle)
+{
+    int         ct     = pOpts->optCt;
+    int         optNo  = 0;
+    tOptDesc *  pOD    = pOpts->pOptDesc;
+    int         docCt  = 0;
+
+    do  {
+        /*
+         * no usage --> disallowed on command line (OPTST_NO_COMMAND), or
+         * deprecated -- strongly discouraged (OPTST_DEPRECATED), or
+         * compiled out of current object code (OPTST_OMITTED)
+         */
+        if ((pOD->fOptState & OPTST_NO_USAGE_MASK) != 0) {
+
+            /*
+             * IF      this is a compiled-out option
+             *   *AND* usage was requested with "omitted-usage"
+             *   *AND* this is NOT abbreviated usage
+             * THEN display this option.
+             */
+            if (  (pOD->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
+               && (pOD->pz_Name != NULL)
+               && (ex_code == EXIT_SUCCESS))  {
+
+                char const * why_pz =
+                    (pOD->pzText == NULL) ? zDisabledWhy : pOD->pzText;
+                prt_preamble(pOpts, pOD, &argTypes);
+                fprintf(option_usage_fp, zDisabledOpt, pOD->pz_Name, why_pz);
+            }
+
+            continue;
+        }
+
+        if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
+            if (ex_code == EXIT_SUCCESS) {
+                fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
+                        pOptTitle);
+                docCt++;
+            }
+
+            continue;
+        }
+
+        /* Skip name only options when we have a vendor option */
+        if (  ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
+           && (! IS_GRAPHIC_CHAR(pOD->optValue)))
+            continue;
+
+        /*
+         *  IF       this is the first auto-opt maintained option
+         *    *AND*  we are doing a full help
+         *    *AND*  there are documentation options
+         *    *AND*  the last one was not a doc option,
+         *  THEN document that the remaining options are not user opts
+         */
+        if ((docCt > 0) && (ex_code == EXIT_SUCCESS)) {
+            if (pOpts->presetOptCt == optNo) {
+                if ((pOD[-1].fOptState & OPTST_DOCUMENT) == 0)
+                    fprintf(option_usage_fp, argTypes.pzBrk, zAuto, pOptTitle);
+
+            } else if ((ct == 1) &&
+                       (pOpts->fOptSet & OPTPROC_VENDOR_OPT))
+                fprintf(option_usage_fp, argTypes.pzBrk, zVendIntro, pOptTitle);
+        }
+
+        prt_one_usage(pOpts, pOD, &argTypes);
+
+        /*
+         *  IF we were invoked because of the --help option,
+         *  THEN print all the extra info
+         */
+        if (ex_code == EXIT_SUCCESS)
+            prt_extd_usage(pOpts, pOD, &argTypes, pOptTitle);
+
+    } while (pOD++, optNo++, (--ct > 0));
+
+    fputc('\n', option_usage_fp);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   PROGRAM DETAILS
+ */
+static void
+prt_prog_detail(tOptions* pOptions)
+{
+    ag_bool  initIntro = AG_TRUE;
+
+    /*
+     *  Display all the places we look for config files
+     */
+    prt_ini_list(pOptions->papzHomeList, &initIntro,
+                 pOptions->pzRcName, pOptions->pzProgPath);
+
+    /*
+     *  Let the user know about environment variable settings
+     */
+    if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) {
+        if (initIntro)
+            fputs(zPresetIntro, option_usage_fp);
+
+        fprintf(option_usage_fp, zExamineFmt, pOptions->pzPROGNAME);
+    }
+
+    /*
+     *  IF we found an enumeration,
+     *  THEN hunt for it again.  Call the handler proc with a NULL
+     *       option struct pointer.  That tells it to display the keywords.
+     */
+    if (displayEnum) {
+        int        ct     = pOptions->optCt;
+        int        optNo  = 0;
+        tOptDesc*  pOD    = pOptions->pOptDesc;
+
+        fputc('\n', option_usage_fp);
+        fflush(option_usage_fp);
+        do  {
+            switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
+            case OPARG_TYPE_ENUMERATION:
+            case OPARG_TYPE_MEMBERSHIP:
+                (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
+            }
+        } while (pOD++, optNo++, (--ct > 0));
+    }
+
+    /*
+     *  If there is a detail string, now is the time for that.
+     */
+    if (pOptions->pzDetail != NULL)
+        fputs(pOptions->pzDetail, option_usage_fp);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   OPTION LINE FORMATTING SETUP
+ *
+ *  The "OptFmt" formats receive three arguments:
+ *  1.  the type of the option's argument
+ *  2.  the long name of the option
+ *  3.  "YES" or "no ", depending on whether or not the option must appear
+ *      on the command line.
+ *  These formats are used immediately after the option flag (if used) has
+ *  been printed.
+ *
+ *  Set up the formatting for GNU-style output
+ */
+static int
+setGnuOptFmts(tOptions* pOpts, tCC** ppT)
+{
+    static char const zOneSpace[] = " ";
+    int  flen = 22;
+    *ppT = zNoRq_ShrtTtl;
+
+    argTypes.pzStr  = zGnuStrArg;
+    argTypes.pzReq  = zOneSpace;
+    argTypes.pzNum  = zGnuNumArg;
+    argTypes.pzKey  = zGnuKeyArg;
+    argTypes.pzKeyL = zGnuKeyLArg;
+    argTypes.pzTime = zGnuTimeArg;
+    argTypes.pzFile = zGnuFileArg;
+    argTypes.pzBool = zGnuBoolArg;
+    argTypes.pzNest = zGnuNestArg;
+    argTypes.pzOpt  = zGnuOptArg;
+    argTypes.pzNo   = zOneSpace;
+    argTypes.pzBrk  = zGnuBreak;
+    argTypes.pzNoF  = zSixSpaces;
+    argTypes.pzSpc  = zThreeSpaces;
+
+    switch (pOpts->fOptSet & OPTPROC_L_N_S) {
+    case OPTPROC_L_N_S:    argTypes.pzOptFmt = zGnuOptFmt;     break;
+    case OPTPROC_LONGOPT:  argTypes.pzOptFmt = zGnuOptFmt;     break;
+    case 0:                argTypes.pzOptFmt = zGnuOptFmt + 2; break;
+    case OPTPROC_SHORTOPT:
+        argTypes.pzOptFmt = zShrtGnuOptFmt;
+        zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
+        argTypes.pzOpt = " [arg]";
+        flen = 8;
+        break;
+    }
+
+    return flen;
+}
+
+
+/*
+ *  Standard (AutoOpts normal) option line formatting
+ */
+static int
+setStdOptFmts(tOptions* pOpts, tCC** ppT)
+{
+    int  flen = 0;
+
+    argTypes.pzStr  = zStdStrArg;
+    argTypes.pzReq  = zStdReqArg;
+    argTypes.pzNum  = zStdNumArg;
+    argTypes.pzKey  = zStdKeyArg;
+    argTypes.pzKeyL = zStdKeyLArg;
+    argTypes.pzTime = zStdTimeArg;
+    argTypes.pzFile = zStdFileArg;
+    argTypes.pzBool = zStdBoolArg;
+    argTypes.pzNest = zStdNestArg;
+    argTypes.pzOpt  = zStdOptArg;
+    argTypes.pzNo   = zStdNoArg;
+    argTypes.pzBrk  = zStdBreak;
+    argTypes.pzNoF  = zFiveSpaces;
+    argTypes.pzSpc  = zTwoSpaces;
+
+    switch (pOpts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
+    case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
+        *ppT = zNoRq_ShrtTtl;
+        argTypes.pzOptFmt = zNrmOptFmt;
+        flen = 19;
+        break;
+
+    case OPTPROC_NO_REQ_OPT:
+        *ppT = zNoRq_NoShrtTtl;
+        argTypes.pzOptFmt = zNrmOptFmt;
+        flen = 19;
+        break;
+
+    case OPTPROC_SHORTOPT:
+        *ppT = zReq_ShrtTtl;
+        argTypes.pzOptFmt = zReqOptFmt;
+        flen = 24;
+        break;
+
+    case 0:
+        *ppT = zReq_NoShrtTtl;
+        argTypes.pzOptFmt = zReqOptFmt;
+        flen = 24;
+    }
+
+    return flen;
+}
+
+
+/*:
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/usage.c */
diff --git a/libopts/value-type.c b/libopts/value-type.c
new file mode 100644 (file)
index 0000000..ff98c0a
--- /dev/null
@@ -0,0 +1,123 @@
+/* ANSI-C code produced by gperf version 3.0.4 */
+
+
+#if 0 /* gperf build options: */
+// %struct-type
+// %language=ANSI-C
+// %includes
+// %global-table
+// %omit-struct-type
+// %readonly-tables
+// %compare-strncmp
+// 
+// %define slot-name               vtp_name
+// %define hash-function-name      value_type_hash
+// %define lookup-function-name    find_value_type_name
+// %define word-array-name         value_type_table
+// %define initializer-suffix      ,VTP_COUNT_KWD
+#endif /* gperf build options: */
+
+#include "value-type.h"
+
+typedef struct {
+    char const *    vtp_name;
+    value_type_enum_t   vtp_id;
+} value_type_map_t;
+#include <string.h>
+
+/* maximum key range = 20, duplicates = 0 */
+
+#ifdef __GNUC__
+#else
+#ifdef __cplusplus
+#endif
+#endif
+inline static unsigned int
+value_type_hash (register const char *str, register unsigned int len)
+{
+  static const unsigned char asso_values[] =
+    {
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 10, 23, 23, 23, 23, 23, 23, 23, 23,
+      23,  5, 23, 23,  5,  0,  0, 23, 15, 23,
+      23, 10, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+      23, 23, 23, 23, 23, 23
+    };
+  return len + asso_values[(unsigned char)str[2]];
+}
+
+static const value_type_map_t value_type_table[] =
+  {
+    {"",VTP_COUNT_KWD}, {"",VTP_COUNT_KWD},
+    {"",VTP_COUNT_KWD},
+    {"set",             VTP_KWD_SET},
+    {"",VTP_COUNT_KWD}, {"",VTP_COUNT_KWD},
+    {"nested",          VTP_KWD_NESTED},
+    {"integer",         VTP_KWD_INTEGER},
+    {"",VTP_COUNT_KWD},
+    {"bool",            VTP_KWD_BOOL},
+    {"",VTP_COUNT_KWD},
+    {"string",          VTP_KWD_STRING},
+    {"boolean",         VTP_KWD_BOOLEAN},
+    {"",VTP_COUNT_KWD},
+    {"set-membership",  VTP_KWD_SET_MEMBERSHIP},
+    {"",VTP_COUNT_KWD}, {"",VTP_COUNT_KWD},
+    {"keyword",         VTP_KWD_KEYWORD},
+    {"",VTP_COUNT_KWD},
+    {"hierarchy",       VTP_KWD_HIERARCHY},
+    {"",VTP_COUNT_KWD}, {"",VTP_COUNT_KWD},
+    {"invalid",         VTP_KWD_INVALID}
+  };
+
+#ifdef __GNUC__
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+static inline const value_type_map_t *
+find_value_type_name (register const char *str, register unsigned int len)
+{
+  if (len <= 14 && len >= 3)
+    {
+      register int key = value_type_hash (str, len);
+
+      if (key <= 22 && key >= 0)
+        {
+          register const char *s = value_type_table[key].vtp_name;
+
+          if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+            return &value_type_table[key];
+        }
+    }
+  return 0;
+}
+
+
+value_type_enum_t
+find_value_type_id(char const * str, unsigned int len)
+{
+    const value_type_map_t * p =
+        find_value_type_name(str, len);
+    return (p == 0) ? VTP_KWD_INVALID : p->vtp_id;
+}
diff --git a/libopts/value-type.h b/libopts/value-type.h
new file mode 100644 (file)
index 0000000..28ee23e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  Generated header for gperf generated source Thu Dec 29 12:02:33 PST 2011
+ *  This file enumerates the list of names and declares the
+ *  procedure for mapping string names to the enum value.
+ */
+#ifndef AUTOOPTS_VALUE_TYPE_H_GUARD
+#define AUTOOPTS_VALUE_TYPE_H_GUARD 1
+
+typedef enum {
+    VTP_KWD_INVALID,
+    VTP_KWD_STRING,
+    VTP_KWD_INTEGER,
+    VTP_KWD_BOOLEAN,
+    VTP_KWD_BOOL,
+    VTP_KWD_KEYWORD,
+    VTP_KWD_SET,
+    VTP_KWD_SET_MEMBERSHIP,
+    VTP_KWD_NESTED,
+    VTP_KWD_HIERARCHY,
+    VTP_COUNT_KWD
+} value_type_enum_t;
+
+extern value_type_enum_t
+find_value_type_id(char const * str, unsigned int len);
+#endif /* AUTOOPTS_VALUE_TYPE_H_GUARD */
diff --git a/libopts/version.c b/libopts/version.c
new file mode 100644 (file)
index 0000000..1ebf93f
--- /dev/null
@@ -0,0 +1,196 @@
+
+/*
+ * Time-stamp:      "2011-05-02 12:04:47 bkorb"
+ *
+ *  This module implements the default usage procedure for
+ *  Automated Options.  It may be overridden, of course.
+ */
+
+/*
+ *  This file is part of AutoOpts, a companion to AutoGen.
+ *  AutoOpts is free software.
+ *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+ *
+ *  AutoOpts is available under any one of two licenses.  The license
+ *  in use must be one of these two and the choice is under the control
+ *  of the user of the license.
+ *
+ *   The GNU Lesser General Public License, version 3 or later
+ *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ *   The Modified Berkeley Software Distribution License
+ *      See the file "COPYING.mbsd"
+ *
+ *  These files have the following md5sums:
+ *
+ *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+/*=export_func  optionVersion
+ *
+ * what:     return the compiled AutoOpts version number
+ * ret_type: char const*
+ * ret_desc: the version string in constant memory
+ * doc:
+ *  Returns the full version string compiled into the library.
+ *  The returned string cannot be modified.
+=*/
+char const*
+optionVersion(void)
+{
+    static char const zVersion[] =
+        STR(AO_CURRENT.AO_REVISION);
+
+    return zVersion;
+}
+
+static void
+emit_simple_ver(tOptions * pOpts, FILE * fp)
+{
+    if (pOpts->pzFullVersion != NULL)
+        fputs(pOpts->pzFullVersion, fp);
+
+    else if (pOpts->pzCopyright != NULL) {
+        char const * pe = strchr(pOpts->pzCopyright, '\n');
+        if (pe == NULL)
+            pe = pOpts->pzCopyright + strlen(pOpts->pzCopyright);
+        fwrite(pOpts->pzCopyright, 1, pe - pOpts->pzCopyright, fp);
+    }
+
+    else {
+        char const * pe = strchr(pOpts->pzUsageTitle, '\n');
+        if (pe == NULL)
+            pe = pOpts->pzUsageTitle + strlen(pOpts->pzUsageTitle);
+        fwrite(pOpts->pzUsageTitle, 1, pe - pOpts->pzCopyright, fp);
+    }
+    fputc('\n', fp);
+}
+
+static void
+emit_copy_ver(tOptions * pOpts, FILE * fp)
+{
+    if (pOpts->pzCopyright != NULL)
+        fputs(pOpts->pzCopyright, fp);
+
+    else if (pOpts->pzFullVersion != NULL)
+        fputs(pOpts->pzFullVersion, fp);
+
+    else {
+        char const * pe = strchr(pOpts->pzUsageTitle, '\n');
+        if (pe == NULL)
+            pe = pOpts->pzUsageTitle + strlen(pOpts->pzUsageTitle);
+        fwrite(pOpts->pzUsageTitle, 1, pe - pOpts->pzCopyright, fp);
+    }
+
+    fputc('\n', fp);
+
+    if (HAS_pzPkgDataDir(pOpts) && (pOpts->pzPackager != NULL))
+        fputs(pOpts->pzPackager, fp);
+
+    else if (pOpts->pzBugAddr != NULL)
+        fprintf(fp, zPlsSendBugs, pOpts->pzBugAddr);
+}
+
+static void
+emit_copy_note(tOptions * pOpts, FILE * fp)
+{
+    if (pOpts->pzCopyright != NULL) {
+        fputs(pOpts->pzCopyright, fp);
+        fputc('\n', fp);
+    }
+
+    if (pOpts->pzCopyNotice != NULL) {
+        fputs(pOpts->pzCopyNotice, fp);
+        fputc('\n', fp);
+    }
+
+    fprintf(fp, zAO_Ver, optionVersion());
+
+    if (HAS_pzPkgDataDir(pOpts) && (pOpts->pzPackager != NULL))
+        fputs(pOpts->pzPackager, fp);
+
+    else if (pOpts->pzBugAddr != NULL)
+        fprintf(fp, zPlsSendBugs, pOpts->pzBugAddr);
+}
+
+static void
+print_ver(tOptions * pOpts, tOptDesc * pOD, FILE * fp)
+{
+    char ch;
+
+    /*
+     *  IF we have an argument for this option, use it
+     *  Otherwise, default to version only or copyright note,
+     *  depending on whether the layout is GNU standard form or not.
+     */
+    if (  (pOD->fOptState & OPTST_ARG_OPTIONAL)
+       && (pOD->optArg.argString != NULL)
+       && (pOD->optArg.argString[0] != NUL))
+
+        ch = pOD->optArg.argString[0];
+
+    else {
+        set_usage_flags(pOpts, NULL);
+        ch = (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? 'c' : 'v';
+    }
+
+    switch (ch) {
+    case NUL: /* arg provided, but empty */
+    case 'v': case 'V': emit_simple_ver(pOpts, fp); break;
+    case 'c': case 'C': emit_copy_ver(pOpts, fp);   break;
+    case 'n': case 'N': emit_copy_note(pOpts, fp);  break;
+
+    default:
+        fprintf(stderr, zBadVerArg, ch);
+        exit(EXIT_FAILURE);
+    }
+
+    fflush(fp);
+    if (ferror(fp) != 0) {
+        fputs(zOutputFail, stderr);
+        exit(EXIT_FAILURE);
+    }
+    exit(EXIT_SUCCESS);
+}
+
+/*=export_func  optionPrintVersion
+ * private:
+ *
+ * what:  Print the program version
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  This routine will print the version to stdout.
+=*/
+void
+optionPrintVersion(tOptions * pOpts, tOptDesc * pOD)
+{
+    print_ver(pOpts, pOD, stdout);
+}
+
+/*=export_func  optionVersionStderr
+ * private:
+ *
+ * what:  Print the program version to stderr
+ * arg:   + tOptions* + pOpts    + program options descriptor +
+ * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
+ *
+ * doc:
+ *  This routine will print the version to stderr.
+=*/
+void
+optionVersionStderr(tOptions * pOpts, tOptDesc * pOD)
+{
+    print_ver(pOpts, pOD, stderr);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/version.c */
diff --git a/libopts/xat-attribute.c b/libopts/xat-attribute.c
new file mode 100644 (file)
index 0000000..db47531
--- /dev/null
@@ -0,0 +1,114 @@
+/* ANSI-C code produced by gperf version 3.0.4 */
+
+
+#if 0 /* gperf build options: */
+// %struct-type
+// %language=ANSI-C
+// %includes
+// %global-table
+// %omit-struct-type
+// %readonly-tables
+// %compare-strncmp
+// 
+// %define slot-name               xat_name
+// %define hash-function-name      xat_attribute_hash
+// %define lookup-function-name    find_xat_attribute_name
+// %define word-array-name         xat_attribute_table
+// %define initializer-suffix      ,XAT_COUNT_KWD
+#endif /* gperf build options: */
+
+#include "xat-attribute.h"
+
+typedef struct {
+    char const *    xat_name;
+    xat_attribute_enum_t   xat_id;
+} xat_attribute_map_t;
+#include <string.h>
+
+/* maximum key range = 9, duplicates = 0 */
+
+#ifdef __GNUC__
+#else
+#ifdef __cplusplus
+#endif
+#endif
+inline static unsigned int
+xat_attribute_hash (register const char *str, register unsigned int len)
+{
+  static const unsigned char asso_values[] =
+    {
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13,  0,
+      13, 13, 13, 13, 13,  5, 13,  5, 13,  0,
+      13, 13, 13, 13, 13, 13,  0,  0, 13,  0,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 13, 13, 13, 13
+    };
+  return len + asso_values[(unsigned char)str[0]];
+}
+
+static const xat_attribute_map_t xat_attribute_table[] =
+  {
+    {"",XAT_COUNT_KWD}, {"",XAT_COUNT_KWD},
+    {"",XAT_COUNT_KWD}, {"",XAT_COUNT_KWD},
+    {"type",            XAT_KWD_TYPE},
+    {"words",           XAT_KWD_WORDS},
+    {"cooked",          XAT_KWD_COOKED},
+    {"members",         XAT_KWD_MEMBERS},
+    {"uncooked",        XAT_KWD_UNCOOKED},
+    {"keep",            XAT_KWD_KEEP},
+    {"",XAT_COUNT_KWD}, {"",XAT_COUNT_KWD},
+    {"invalid",         XAT_KWD_INVALID}
+  };
+
+#ifdef __GNUC__
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+static inline const xat_attribute_map_t *
+find_xat_attribute_name (register const char *str, register unsigned int len)
+{
+  if (len <= 8 && len >= 4)
+    {
+      register int key = xat_attribute_hash (str, len);
+
+      if (key <= 12 && key >= 0)
+        {
+          register const char *s = xat_attribute_table[key].xat_name;
+
+          if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+            return &xat_attribute_table[key];
+        }
+    }
+  return 0;
+}
+
+
+xat_attribute_enum_t
+find_xat_attribute_id(char const * str, unsigned int len)
+{
+    const xat_attribute_map_t * p =
+        find_xat_attribute_name(str, len);
+    return (p == 0) ? XAT_KWD_INVALID : p->xat_id;
+}
diff --git a/libopts/xat-attribute.h b/libopts/xat-attribute.h
new file mode 100644 (file)
index 0000000..cbcf6e5
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *  Generated header for gperf generated source Thu Dec 29 12:02:33 PST 2011
+ *  This file enumerates the list of names and declares the
+ *  procedure for mapping string names to the enum value.
+ */
+#ifndef AUTOOPTS_XAT_ATTRIBUTE_H_GUARD
+#define AUTOOPTS_XAT_ATTRIBUTE_H_GUARD 1
+
+typedef enum {
+    XAT_KWD_INVALID,
+    XAT_KWD_TYPE,
+    XAT_KWD_WORDS,
+    XAT_KWD_MEMBERS,
+    XAT_KWD_COOKED,
+    XAT_KWD_UNCOOKED,
+    XAT_KWD_KEEP,
+    XAT_COUNT_KWD
+} xat_attribute_enum_t;
+
+extern xat_attribute_enum_t
+find_xat_attribute_id(char const * str, unsigned int len);
+#endif /* AUTOOPTS_XAT_ATTRIBUTE_H_GUARD */
diff --git a/m4/libopts.m4 b/m4/libopts.m4
new file mode 100644 (file)
index 0000000..b18e86d
--- /dev/null
@@ -0,0 +1,582 @@
+dnl  -*- buffer-read-only: t -*- vi: set ro:
+dnl 
+dnl DO NOT EDIT THIS FILE   (libopts.m4)
+dnl 
+dnl It has been AutoGen-ed  December 29, 2011 at 12:02:31 PM by AutoGen 5.14
+dnl From the definitions    libopts.def
+dnl and the template file   conftest.tpl
+dnl
+dnl do always before generated macros:
+dnl
+AC_DEFUN([INVOKE_LIBOPTS_MACROS_FIRST],[
+  AC_REQUIRE([AC_HEADER_STDC])
+  AC_HEADER_DIRENT
+  
+  # =================
+  # AC_CHECK_HEADERS
+  # =================
+  AC_CHECK_HEADERS([ \
+      dlfcn.h      errno.h       fcntl.h       libgen.h     \
+      memory.h     netinet/in.h  setjmp.h      sys/mman.h   \
+      sys/param.h  sys/poll.h    sys/procset.h sys/select.h \
+      sys/socket.h sys/stropts.h sys/time.h    sys/un.h     \
+      sys/wait.h   unistd.h      utime.h       sysexits.h ])
+  
+  AC_CHECK_HEADERS([stdarg.h     varargs.h],
+      [lo_have_arg_hdr=true;break],
+      [lo_have_arg_hdr=false])
+  
+  AC_CHECK_HEADERS([string.h     strings.h],
+      [lo_have_str_hdr=true;break],
+      [lo_have_str_hdr=false])
+  
+  AC_CHECK_HEADERS([limits.h     sys/limits.h  values.h],
+      [lo_have_lim_hdr=true;break],
+      [lo_have_lim_hdr=false])
+  
+  AC_CHECK_HEADERS([inttypes.h   stdint.h],
+      [lo_have_typ_hdr=true;break],
+      [lo_have_typ_hdr=false])
+  
+  # ----------------------------------------------------------------------
+  # check for various programs used during the build.
+  # On OS/X, "wchar.h" needs "runetype.h" to work properly.
+  # ----------------------------------------------------------------------
+  AC_CHECK_HEADERS([runetype.h wchar.h], [], [],[
+  AC_INCLUDES_DEFAULT
+  #if HAVE_RUNETYPE_H
+  # include <runetype.h>
+  #endif
+  ])
+  
+  # --------------------------------------------
+  # Verify certain entries from AC_CHECK_HEADERS
+  # --------------------------------------------
+  [for f in sys_types sys_mman sys_param sys_stat sys_wait \
+           string errno stdlib memory setjmp
+  do eval as_ac_var=\${ac_cv_header_${f}_h+set}
+     test "${as_ac_var}" = set || {
+       ]AC_MSG_ERROR([You must have ${f}.h on your system])[
+     }
+  done
+  
+  ${lo_have_arg_hdr} || \
+    ]AC_MSG_ERROR([You must have stdarg.h or varargs.h on your system])[
+  
+  ${lo_have_str_hdr} || \
+    ]AC_MSG_ERROR([You must have string.h or strings.h on your system])[
+  
+  ${lo_have_lim_hdr} || \
+    ]AC_MSG_ERROR(
+      [You must have one of limits.h, sys/limits.h or values.h])[
+  
+  ${lo_have_typ_hdr} || \
+    ]AC_MSG_ERROR([You must have inttypes.h or stdint.h on your system])
+  
+  # ----------------------------------------------------------------------
+  # Checks for typedefs
+  # ----------------------------------------------------------------------
+  AC_CHECK_TYPES(wchar_t)
+  AC_CHECK_TYPES(wint_t, [], [], [
+  AC_INCLUDES_DEFAULT
+  #if HAVE_RUNETYPE_H
+  # include <runetype.h>
+  #endif
+  #if HAVE_WCHAR_H
+  # include <wchar.h>
+  #endif
+  ])
+  AC_CHECK_TYPES([int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+     intptr_t, uintptr_t, uint_t, pid_t, size_t])
+  
+  # =====
+  # sizes
+  # =====
+  AC_CHECK_SIZEOF(char*, 8)
+  AC_CHECK_SIZEOF(int,   4)
+  AC_CHECK_SIZEOF(long,  8)
+  AC_CHECK_SIZEOF(short, 2)
+  
+  # ----------------------------------------------------------------------
+  # AC_CHECK_LIB for SVR4 libgen, and use it if it defines pathfind.
+  # ----------------------------------------------------------------------
+  AC_CHECK_LIB(gen, pathfind)
+  AC_FUNC_VPRINTF
+  AC_FUNC_FORK
+  AC_CHECK_FUNCS([mmap canonicalize_file_name snprintf strdup strchr \
+                 strrchr strsignal])
+  AC_PROG_SED
+  [while :
+  do
+      POSIX_SHELL=`which bash`
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=`which dash`
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=/usr/xpg4/bin/sh
+      test -x "$POSIX_SHELL" && break
+      POSIX_SHELL=`/bin/sh -c '
+          exec 2>/dev/null
+          if ! true ; then exit 1 ; fi
+          echo /bin/sh'`
+      test -x "$POSIX_SHELL" && break
+      ]AC_ERROR([Cannot locate a working POSIX shell])[
+  done]
+  AC_DEFINE_UNQUOTED([POSIX_SHELL], ["${POSIX_SHELL}"],
+           [define to a working POSIX compliant shell])
+  AC_SUBST([POSIX_SHELL])
+])
+
+dnl
+dnl @synopsis  INVOKE_LIBOPTS_MACROS
+dnl
+dnl  This macro will invoke the AutoConf macros specified in libopts.def
+dnl  that have not been disabled with "omit-invocation".
+dnl
+AC_DEFUN([LIBOPTS_WITH_REGEX_HEADER],[
+  AC_ARG_WITH([regex-header],
+    AS_HELP_STRING([--with-regex-header], [a reg expr header is specified]),
+    [libopts_cv_with_regex_header=${with_regex_header}],
+    AC_CACHE_CHECK([whether a reg expr header is specified], libopts_cv_with_regex_header,
+      libopts_cv_with_regex_header=no)
+  ) # end of AC_ARG_WITH
+  if test "X${libopts_cv_with_regex_header}" != Xno
+  then
+    AC_DEFINE_UNQUOTED([REGEX_HEADER],[<${libopts_cv_with_regex_header}>])
+  else
+    AC_DEFINE([REGEX_HEADER],[<regex.h>],[name of regex header file])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_WITH_REGEX_HEADER
+
+
+AC_DEFUN([LIBOPTS_WITHLIB_REGEX],[
+  AC_ARG_WITH([libregex],
+    AS_HELP_STRING([--with-libregex], [libregex installation prefix]),
+    [libopts_cv_with_libregex_root=${with_libregex}],
+    AC_CACHE_CHECK([whether with-libregex was specified], libopts_cv_with_libregex_root,
+      libopts_cv_with_libregex_root=no)
+  ) # end of AC_ARG_WITH libregex
+
+  if test "${with_libregex+set}" = set && \
+     test "${withval}" = no
+  then ## disabled by request
+    libopts_cv_with_libregex_root=no
+    libopts_cv_with_libregex_cflags=no
+    libopts_cv_with_libregex_libs=no
+  else
+
+  AC_ARG_WITH([libregex-cflags],
+    AS_HELP_STRING([--with-libregex-cflags], [libregex compile flags]),
+    [libopts_cv_with_libregex_cflags=${with_regex_cflags}],
+    AC_CACHE_CHECK([whether with-libregex-cflags was specified], libopts_cv_with_libregex_cflags,
+      libopts_cv_with_libregex_cflags=no)
+  ) # end of AC_ARG_WITH libregex-cflags
+
+  AC_ARG_WITH([libregex-libs],
+    AS_HELP_STRING([--with-libregex-libs], [libregex link command arguments]),
+    [libopts_cv_with_libregex_libs=${with_regex_libs}],
+    AC_CACHE_CHECK([whether with-libregex-libs was specified], libopts_cv_with_libregex_libs,
+      libopts_cv_with_libregex_libs=no)
+  ) # end of AC_ARG_WITH libregex-libs
+
+  case "X${libopts_cv_with_libregex_cflags}" in
+  Xyes|Xno|X )
+    case "X${libopts_cv_with_libregex_root}" in
+    Xyes|Xno|X ) libopts_cv_with_libregex_cflags=no ;;
+    * )        libopts_cv_with_libregex_cflags=-I${libopts_cv_with_libregex_root}/include ;;
+    esac
+  esac
+  case "X${libopts_cv_with_libregex_libs}" in
+  Xyes|Xno|X )
+    case "X${libopts_cv_with_libregex_root}" in
+    Xyes|Xno|X ) libopts_cv_with_libregex_libs=no ;;
+    * )        libopts_cv_with_libregex_libs="-L${libopts_cv_with_libregex_root}/lib -lregex";;
+    esac
+  esac
+  libopts_save_CPPFLAGS="${CPPFLAGS}"
+  libopts_save_LIBS="${LIBS}"
+  fi ## disabled by request
+
+  case "X${libopts_cv_with_libregex_cflags}" in
+  Xyes|Xno|X )
+    libopts_cv_with_libregex_cflags="" ;;
+  * ) CPPFLAGS="${CPPFLAGS} ${libopts_cv_with_libregex_cflags}" ;;
+  esac
+  case "X${libopts_cv_with_libregex_libs}" in
+  Xyes|Xno|X )
+    libopts_cv_with_libregex_libs="" ;;
+  * )
+    LIBS="${LIBS} ${libopts_cv_with_libregex_libs}" ;;
+  esac
+  LIBREGEX_CFLAGS=""
+  LIBREGEX_LIBS=""
+  AC_MSG_CHECKING([whether libregex functions properly])
+  AC_CACHE_VAL([libopts_cv_with_libregex],[
+  AC_TRY_RUN([@%:@include <stdio.h>
+@%:@include <stdlib.h>
+@%:@include <sys/types.h>
+@%:@include REGEX_HEADER
+static regex_t re;
+void comp_re( char const* pzPat ) {
+  int res = regcomp( &re, pzPat, REG_EXTENDED|REG_ICASE|REG_NEWLINE );
+  if (res == 0) return;
+  exit( res ); }
+int main() {
+  regmatch_t m@<:@2@:>@;
+  comp_re( "^.*\@S|@"   );
+  comp_re( "()|no.*" );
+  comp_re( "."       );
+  if (regexec( &re, "X", 2, m, 0 ) != 0)  return 1;
+  if ((m@<:@0@:>@.rm_so != 0) || (m@<:@0@:>@.rm_eo != 1)) {
+    fputs( "error: regex -->.<-- did not match\n", stderr );
+    return 1;
+  }
+  return 0; }],
+    [libopts_cv_with_libregex=yes], [libopts_cv_with_libregex=no],
+    [libopts_cv_with_libregex=no]) # end of AC_TRY_RUN 
+  ]) # end of AC_CACHE_VAL for libopts_cv_with_libregex
+  AC_MSG_RESULT([${libopts_cv_with_libregex}])
+  if test "X${libopts_cv_with_libregex}" != Xno
+  then
+    AC_DEFINE([WITH_LIBREGEX],[1],
+        [Define this if a working libregex can be found])
+  else
+    CPPFLAGS="${libopts_save_CPPFLAGS}"
+    LIBS="${libopts_save_LIBS}"
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_WITHLIB_REGEX
+
+
+AC_DEFUN([LIBOPTS_RUN_PATHFIND],[
+  AC_MSG_CHECKING([whether pathfind(3) works])
+  AC_CACHE_VAL([libopts_cv_run_pathfind],[
+  AC_TRY_RUN([@%:@include <string.h>
+@%:@include <stdlib.h>
+int main (int argc, char** argv) {
+   char* pz = pathfind( getenv( "PATH" ), "sh", "x" );
+   return (pz == 0) ? 1 : 0;
+}],
+    [libopts_cv_run_pathfind=yes],[libopts_cv_run_pathfind=no],[libopts_cv_run_pathfind=no]
+  ) # end of TRY_RUN
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_pathfind
+  AC_MSG_RESULT([${libopts_cv_run_pathfind}])
+  if test "X${libopts_cv_run_pathfind}" != Xno
+  then
+    AC_DEFINE([HAVE_PATHFIND],[1],
+        [Define this if pathfind(3) works])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_RUN_PATHFIND
+
+
+AC_DEFUN([LIBOPTS_TEST_DEV_ZERO],[
+  AC_MSG_CHECKING([whether /dev/zero is readable device])
+  AC_CACHE_VAL([libopts_cv_test_dev_zero],[
+    libopts_cv_test_dev_zero=`exec 2> /dev/null
+dzero=\`ls -lL /dev/zero | egrep ^c......r\`
+test -z "${dzero}" && exit 1
+echo ${dzero}`
+    if test $? -ne 0 || test -z "$libopts_cv_test_dev_zero"
+    then libopts_cv_test_dev_zero=no
+    fi
+  ]) # end of CACHE_VAL of libopts_cv_test_dev_zero
+  AC_MSG_RESULT([${libopts_cv_test_dev_zero}])
+  if test "X${libopts_cv_test_dev_zero}" != Xno
+  then
+    AC_DEFINE([HAVE_DEV_ZERO],[1],
+        [Define this if /dev/zero is readable device])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_TEST_DEV_ZERO
+
+
+AC_DEFUN([LIBOPTS_RUN_REALPATH],[
+  AC_MSG_CHECKING([whether we have a functional realpath(3C)])
+  AC_CACHE_VAL([libopts_cv_run_realpath],[
+  AC_TRY_RUN([@%:@include <limits.h>
+@%:@include <stdlib.h>
+int main (int argc, char** argv) {
+@%:@ifndef PATH_MAX
+choke me!!
+@%:@else
+   char zPath@<:@PATH_MAX+1@:>@;
+@%:@endif
+   char *pz = realpath(argv@<:@0@:>@, zPath);
+   return (pz == zPath) ? 0 : 1;
+}],
+    [libopts_cv_run_realpath=yes],[libopts_cv_run_realpath=no],[libopts_cv_run_realpath=no]
+  ) # end of TRY_RUN
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_realpath
+  AC_MSG_RESULT([${libopts_cv_run_realpath}])
+  if test "X${libopts_cv_run_realpath}" != Xno
+  then
+    AC_DEFINE([HAVE_REALPATH],[1],
+        [Define this if we have a functional realpath(3C)])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_RUN_REALPATH
+
+
+AC_DEFUN([LIBOPTS_RUN_STRFTIME],[
+  AC_MSG_CHECKING([whether strftime() works])
+  AC_CACHE_VAL([libopts_cv_run_strftime],[
+  AC_TRY_RUN([@%:@include <time.h>
+@%:@include <string.h>
+char t_buf@<:@ 64 @:>@;
+int main() {
+  static char const z@<:@@:>@ = "Thursday Aug 28 240";
+  struct tm tm;
+  tm.tm_sec   = 36;  /* seconds after the minute @<:@0, 61@:>@  */
+  tm.tm_min   = 44;  /* minutes after the hour @<:@0, 59@:>@ */
+  tm.tm_hour  = 12;  /* hour since midnight @<:@0, 23@:>@ */
+  tm.tm_mday  = 28;  /* day of the month @<:@1, 31@:>@ */
+  tm.tm_mon   =  7;  /* months since January @<:@0, 11@:>@ */
+  tm.tm_year  = 86;  /* years since 1900 */
+  tm.tm_wday  =  4;  /* days since Sunday @<:@0, 6@:>@ */
+  tm.tm_yday  = 239; /* days since January 1 @<:@0, 365@:>@ */
+  tm.tm_isdst =  1;  /* flag for daylight savings time */
+  strftime( t_buf, sizeof( t_buf ), "%A %b %d %j", &tm );
+  return (strcmp( t_buf, z ) != 0); }],
+    [libopts_cv_run_strftime=yes],[libopts_cv_run_strftime=no],[libopts_cv_run_strftime=no]
+  ) # end of TRY_RUN
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_strftime
+  AC_MSG_RESULT([${libopts_cv_run_strftime}])
+  if test "X${libopts_cv_run_strftime}" != Xno
+  then
+    AC_DEFINE([HAVE_STRFTIME],[1],
+        [Define this if strftime() works])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_RUN_STRFTIME
+
+
+AC_DEFUN([LIBOPTS_RUN_FOPEN_BINARY],[
+  AC_MSG_CHECKING([whether fopen accepts "b" mode])
+  AC_CACHE_VAL([libopts_cv_run_fopen_binary],[
+  AC_TRY_RUN([@%:@include <stdio.h>
+int main (int argc, char** argv) {
+FILE* fp = fopen("conftest.@S|@ac_ext", "rb");
+return (fp == NULL) ? 1 : fclose(fp); }],
+    [libopts_cv_run_fopen_binary=yes],[libopts_cv_run_fopen_binary=no],[libopts_cv_run_fopen_binary=no]
+  ) # end of TRY_RUN
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_fopen_binary
+  AC_MSG_RESULT([${libopts_cv_run_fopen_binary}])
+  if test "X${libopts_cv_run_fopen_binary}" != Xno
+  then
+    AC_DEFINE([FOPEN_BINARY_FLAG],"b",
+       [fopen(3) accepts a 'b' in the mode flag])
+  else
+    AC_DEFINE([FOPEN_BINARY_FLAG],"",
+       [fopen(3) accepts a 'b' in the mode flag])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_RUN_FOPEN_BINARY
+
+
+AC_DEFUN([LIBOPTS_RUN_FOPEN_TEXT],[
+  AC_MSG_CHECKING([whether fopen accepts "t" mode])
+  AC_CACHE_VAL([libopts_cv_run_fopen_text],[
+  AC_TRY_RUN([@%:@include <stdio.h>
+int main (int argc, char** argv) {
+FILE* fp = fopen("conftest.@S|@ac_ext", "rt");
+return (fp == NULL) ? 1 : fclose(fp); }],
+    [libopts_cv_run_fopen_text=yes],[libopts_cv_run_fopen_text=no],[libopts_cv_run_fopen_text=no]
+  ) # end of TRY_RUN
+  ]) # end of AC_CACHE_VAL for libopts_cv_run_fopen_text
+  AC_MSG_RESULT([${libopts_cv_run_fopen_text}])
+  if test "X${libopts_cv_run_fopen_text}" != Xno
+  then
+    AC_DEFINE([FOPEN_TEXT_FLAG],"t",
+       [fopen(3) accepts a 't' in the mode flag])
+  else
+    AC_DEFINE([FOPEN_TEXT_FLAG],"",
+       [fopen(3) accepts a 't' in the mode flag])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_RUN_FOPEN_TEXT
+
+
+AC_DEFUN([LIBOPTS_DISABLE_OPTIONAL_ARGS],[
+  AC_ARG_ENABLE([optional-args],
+    AS_HELP_STRING([--disable-optional-args], [not wanting optional option args]),
+    [libopts_cv_enable_optional_args=${enable_optional_args}],
+    AC_CACHE_CHECK([whether not wanting optional option args], libopts_cv_enable_optional_args,
+      libopts_cv_enable_optional_args=yes)
+  ) # end of AC_ARG_ENABLE
+  if test "X${libopts_cv_enable_optional_args}" = Xno
+  then
+    AC_DEFINE([NO_OPTIONAL_OPT_ARGS], [1],
+          [Define this if optional arguments are disallowed])
+  fi
+  
+]) # end of AC_DEFUN of LIBOPTS_DISABLE_OPTIONAL_ARGS
+
+
+AC_DEFUN([INVOKE_LIBOPTS_MACROS],[
+  AC_REQUIRE([INVOKE_LIBOPTS_MACROS_FIRST])
+  # Check to see if a reg expr header is specified.
+  LIBOPTS_WITH_REGEX_HEADER
+
+  # Check to see if a working libregex can be found.
+  LIBOPTS_WITHLIB_REGEX
+
+  # Check to see if pathfind(3) works.
+  LIBOPTS_RUN_PATHFIND
+
+  # Check to see if /dev/zero is readable device.
+  LIBOPTS_TEST_DEV_ZERO
+
+  # Check to see if we have a functional realpath(3C).
+  LIBOPTS_RUN_REALPATH
+
+  # Check to see if strftime() works.
+  LIBOPTS_RUN_STRFTIME
+
+  # Check to see if fopen accepts "b" mode.
+  LIBOPTS_RUN_FOPEN_BINARY
+
+  # Check to see if fopen accepts "t" mode.
+  LIBOPTS_RUN_FOPEN_TEXT
+
+  # Check to see if not wanting optional option args.
+  LIBOPTS_DISABLE_OPTIONAL_ARGS
+
+]) # end AC_DEFUN of INVOKE_LIBOPTS_MACROS
+
+dnl @synopsis  LIBOPTS_CHECK
+dnl
+dnl Time-stamp:        "2011-12-13 21:26:37 bkorb"
+dnl
+dnl If autoopts-config works, add the linking information to LIBS.
+dnl Otherwise, add ``libopts-${ao_rev}'' to SUBDIRS and run all
+dnl the config tests that the library needs.  Invoke the
+dnl "INVOKE_LIBOPTS_MACROS" macro iff we are building libopts.
+dnl
+dnl  This file is part of AutoGen.
+dnl  AutoGen Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
+dnl
+dnl  AutoGen is free software: you can redistribute it and/or modify it
+dnl  under the terms of the GNU General Public License as published by the
+dnl  Free Software Foundation, either version 3 of the License, or
+dnl  (at your option) any later version.
+dnl
+dnl  AutoGen is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl  See the GNU General Public License for more details.
+dnl
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with this program.  If not, see <http://www.gnu.org/licenses/>.
+dnl
+dnl Default to system libopts
+dnl
+AC_DEFUN([LIBOPTS_CHECK_COMMON],[
+  AC_REQUIRE([INVOKE_LIBOPTS_MACROS_FIRST])
+  [NEED_LIBOPTS_DIR='']
+  m4_pushdef([AO_Libopts_Dir],
+           [ifelse($1, , [libopts], [$1])])
+  AC_ARG_ENABLE([local-libopts],
+    AC_HELP_STRING([--enable-local-libopts],
+       [Use the supplied libopts tearoff code]),[
+    if test x$enableval = xyes ; then
+       AC_MSG_NOTICE([Using supplied libopts tearoff])
+       LIBOPTS_CFLAGS='-I$(top_srcdir)/AO_Libopts_Dir'
+       NEED_LIBOPTS_DIR=true
+       LIBOPTS_LDADD='$(top_builddir)/AO_Libopts_Dir/libopts.la'
+    fi])
+
+  AC_ARG_ENABLE([libopts-install],
+    AC_HELP_STRING([--disable-libopts-install],
+       [Do not install libopts with client installation]))
+  AM_CONDITIONAL([INSTALL_LIBOPTS],[test "X${enable_libopts_install}" != Xno])
+
+  [if test -z "${NEED_LIBOPTS_DIR}" ; then]
+     AC_MSG_CHECKING([whether autoopts-config can be found])
+     AC_ARG_WITH([autoopts-config],
+        AC_HELP_STRING([--with-autoopts-config],
+             [specify the config-info script]),
+        [lo_cv_with_autoopts_config=${with_autoopts_config}],
+        AC_CACHE_CHECK([whether autoopts-config is specified],
+             [lo_cv_with_autoopts_config],
+             [if autoopts-config --help 2>/dev/null 1>&2
+        then lo_cv_with_autoopts_config=autoopts-config
+        elif libopts-config --help 2>/dev/null 1>&2
+        then lo_cv_with_autoopts_config=libopts-config
+        else lo_cv_with_autoopts_config=no ; fi])
+     ) # end of AC_ARG_WITH
+
+     AC_CACHE_VAL([lo_cv_test_autoopts],[
+        if test -z "${lo_cv_with_autoopts_config}" \
+                -o X"${lo_cv_with_autoopts_config}" = Xno
+        then
+           if autoopts-config --help 2>/dev/null 1>&2
+           then lo_cv_with_autoopts_config=autoopts-config
+           elif libopts-config --help 2>/dev/null 1>&2
+           then lo_cv_with_autoopts_config=libopts-config
+           else lo_cv_with_autoopts_config=false ; fi
+        fi
+        lo_cv_test_autoopts=`
+            ${lo_cv_with_autoopts_config} --libs` 2> /dev/null
+        if test $? -ne 0 -o -z "${lo_cv_test_autoopts}"
+        then lo_cv_test_autoopts=no ; fi
+     ]) # end of CACHE_VAL
+     AC_MSG_RESULT([${lo_cv_test_autoopts}])
+
+     [if test "X${lo_cv_test_autoopts}" != Xno
+     then
+        LIBOPTS_LDADD="${lo_cv_test_autoopts}"
+        LIBOPTS_CFLAGS="`${lo_cv_with_autoopts_config} --cflags`"
+     else
+        LIBOPTS_LDADD='$(top_builddir)/]AO_Libopts_Dir[/libopts.la'
+        LIBOPTS_CFLAGS='-I$(top_srcdir)/]AO_Libopts_Dir['
+        NEED_LIBOPTS_DIR=true
+     fi
+  fi # end of if test -z "${NEED_LIBOPTS_DIR}"
+  if test -n "${LIBOPTS_BUILD_BLOCKED}" ; then
+    NEED_LIBOPTS_DIR=''
+  fi]
+  AM_CONDITIONAL([NEED_LIBOPTS], [test -n "${NEED_LIBOPTS_DIR}"])
+  AC_SUBST(LIBOPTS_LDADD)
+  AC_SUBST(LIBOPTS_CFLAGS)
+  AC_SUBST(LIBOPTS_DIR, AO_Libopts_Dir)
+  m4_popdef([AO_Libopts_Dir])
+[# end of AC_DEFUN of LIBOPTS_CHECK_COMMON]
+])
+dnl AC_CONFIG_FILES conditionalization requires using AM_COND_IF, however
+dnl AM_COND_IF is new to Automake 1.11.  To use it on new Automake without
+dnl requiring same, a fallback implementation for older Automake is provided.
+dnl Note that disabling of AC_CONFIG_FILES requires Automake 1.11, this code
+dnl is correct only in terms of m4sh generated script.
+m4_ifndef([AM_COND_IF], [AC_DEFUN([AM_COND_IF], [
+if test -z "$$1_TRUE"; then :
+  m4_n([$2])[]dnl
+m4_ifval([$3],
+[else
+  $3
+])dnl
+fi[]dnl
+])])
+dnl
+AC_DEFUN([LIBOPTS_CHECK_NOBUILD], [
+  m4_pushdef([AO_Libopts_Dir],
+             [ifelse($1, , [libopts], [$1])])
+  LIBOPTS_BUILD_BLOCKED=true
+  LIBOPTS_CHECK_COMMON(AO_Libopts_Dir)
+  m4_popdef([AO_Libopts_Dir])dnl
+# end of AC_DEFUN of LIBOPTS_CHECK_NOBUILD
+])
+dnl
+AC_DEFUN([LIBOPTS_CHECK], [
+  m4_pushdef([AO_Libopts_Dir],
+             [ifelse($1, , [libopts], [$1])])
+  LIBOPTS_BUILD_BLOCKED=''
+  LIBOPTS_CHECK_COMMON(AO_Libopts_Dir)
+  AM_COND_IF([NEED_LIBOPTS], [
+    INVOKE_LIBOPTS_MACROS
+    AC_CONFIG_FILES(AO_Libopts_Dir/Makefile)
+  ])dnl
+  m4_popdef([AO_Libopts_Dir])dnl
+# end of AC_DEFUN of LIBOPTS_CHECK
+])
+
diff --git a/m4/liboptschk.m4 b/m4/liboptschk.m4
new file mode 100644 (file)
index 0000000..48e4ceb
--- /dev/null
@@ -0,0 +1,29 @@
+# liboptschk.m4 serial 2 (autogen - 5.11.4)
+dnl Copyright (c) 2005-2011 by Bruce Korb - all rights reserved
+dnl
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl Time-stamp:        "2010-12-07 12:57:56 bkorb"
+dnl
+AC_DEFUN([ag_FIND_LIBOPTS],
+  [if test "X${ac_cv_header_autoopts_options_h}" = Xno
+  then :
+  else
+    f=`autoopts-config cflags` 2>/dev/null
+    if test X"${f}" = X
+    then
+      :
+    else
+      AC_DEFINE([HAVE_LIBOPTS],[1],[define if we can find libopts])
+      CFLAGS="${CFLAGS} ${f}"
+      ao_CFLAGS="${f}"
+      AC_SUBST(ao_CFLAGS)
+
+      f=`autoopts-config ldflags` 2>/dev/null
+      LIBS="${LIBS} ${f}"
+      ao_LIBS="${f}"
+      AC_SUBST(ao_LIBS)
+    fi
+  fi])
index a23b4b81fcda7bc0324dc09fbbb5e0e924f85707..fcdeb7a033a82530c3edfe8d8b17d438976c775a 100644 (file)
@@ -30,7 +30,8 @@ AM_CPPFLAGS = \
        -I$(builddir)/../lib/includes           \
        -I$(srcdir)/../lib/includes             \
        -I$(srcdir)/../extra/includes   \
-       -I$(srcdir)/cfg
+       -I$(srcdir)/cfg                         \
+       $(LIBOPTS_CFLAGS)
 
 bin_PROGRAMS = gnutls-serv gnutls-cli psktool gnutls-cli-debug
 if ENABLE_PKI
@@ -67,10 +68,10 @@ libcmd_serv_la_SOURCES = serv.gaa serv-gaa.h serv-gaa.c
 
 if ENABLE_SRP
 srptool_SOURCES = srptool.c
-srptool_LDADD = ../lib/libgnutls.la libcmd-srp.la ../gl/libgnu.la
+srptool_LDADD = ../lib/libgnutls.la libcmd-srp.la ../gl/libgnu.la $(LIBOPTS_LDADD)
 noinst_LTLIBRARIES += libcmd-srp.la
 libcmd_srp_la_CFLAGS =
-libcmd_srp_la_SOURCES = srptool.gaa srptool-gaa.h srptool-gaa.c
+libcmd_srp_la_SOURCES = srptool-args.def srptool-args.c srptool-args.h
 endif
 
 if ENABLE_OCSP
@@ -84,25 +85,25 @@ endif
 psktool_SOURCES = psk.c
 psktool_LDADD = ../lib/libgnutls.la libcmd-psk.la ../gl/libgnu.la
 noinst_LTLIBRARIES += libcmd-psk.la
-libcmd_psk_la_CFLAGS =
+libcmd_psk_la_CFLAGS = 
 libcmd_psk_la_SOURCES = psk.gaa psk-gaa.h psk-gaa.c
 
 BENCHMARK_SRCS = benchmark-cipher.c benchmark.c benchmark.h benchmark-tls.c
 
 gnutls_cli_SOURCES = cli.c common.h common.c $(PKCS11_SRCS) $(BENCHMARK_SRCS)
 gnutls_cli_LDADD = ../lib/libgnutls.la
-gnutls_cli_LDADD += libcmd-cli.la ../gl/libgnu.la
+gnutls_cli_LDADD += libcmd-cli.la ../gl/libgnu.la $(LIBOPTS_LDADD)
 gnutls_cli_LDADD += $(LTLIBGCRYPT) $(LIBSOCKET) $(GETADDRINFO_LIB) $(LIB_CLOCK_GETTIME)
 noinst_LTLIBRARIES += libcmd-cli.la
-libcmd_cli_la_CFLAGS =
-libcmd_cli_la_SOURCES = cli.gaa cli-gaa.h cli-gaa.c
+libcmd_cli_la_CFLAGS = 
+libcmd_cli_la_SOURCES = cli-args.def cli-args.c cli-args.h
 
 gnutls_cli_debug_SOURCES = tls_test.c tests.h tests.c common.h common.c $(PKCS11_SRCS)
-gnutls_cli_debug_LDADD = ../lib/libgnutls.la libcmd-cli-debug.la
+gnutls_cli_debug_LDADD = ../lib/libgnutls.la libcmd-cli-debug.la $(LIBOPTS_LDADD)
 gnutls_cli_debug_LDADD += ../gl/libgnu.la $(LIBSOCKET) $(GETADDRINFO_LIB)
 noinst_LTLIBRARIES += libcmd-cli-debug.la
 libcmd_cli_debug_la_CFLAGS =
-libcmd_cli_debug_la_SOURCES = tls_test.gaa tls_test-gaa.h tls_test-gaa.c
+libcmd_cli_debug_la_SOURCES = cli-debug-args.def cli-debug-args.c cli-debug-args.h
 
 #certtool
 
@@ -157,8 +158,6 @@ endif # ENABLE_PKCS11
 
 psk-gaa.c: $(srcdir)/psk.gaa
        -$(GAA) $< -o psk-gaa.c -i psk-gaa.h
-srptool-gaa.c: $(srcdir)/srptool.gaa
-       -$(GAA) $< -o srptool-gaa.c -i srptool-gaa.h
 ocsptool-gaa.c: $(srcdir)/ocsptool.gaa
        -$(GAA) $< -o ocsptool-gaa.c -i ocsptool-gaa.h
 if ENABLE_PKCS11
@@ -167,9 +166,11 @@ p11tool-gaa.c: $(srcdir)/p11tool.gaa
 endif
 certtool-gaa.c: $(srcdir)/certtool.gaa
        -$(GAA) $< -o certtool-gaa.c -i certtool-gaa.h
-cli-gaa.c: $(srcdir)/cli.gaa
-       -$(GAA) $< -o cli-gaa.c -i cli-gaa.h
-tls_test-gaa.c: $(srcdir)/tls_test.gaa
-       -$(GAA) $< -o tls_test-gaa.c -i tls_test-gaa.h
+cli-debug-args.c: $(srcdir)/cli-debug-args.def
+       -autogen $<
+cli-args.c: $(srcdir)/cli-args.def
+       -autogen $<
+srptool-args.c: $(srcdir)/srptool-args.def
+       -autogen $<
 serv-gaa.c: $(srcdir)/serv.gaa
        -$(GAA) $< -o serv-gaa.c -i serv-gaa.h
diff --git a/src/cli-args.c b/src/cli-args.c
new file mode 100644 (file)
index 0000000..9897a3a
--- /dev/null
@@ -0,0 +1,1288 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (cli-args.c)
+ *  
+ *  It has been AutoGen-ed  January 19, 2012 at 09:24:21 PM by AutoGen 5.12
+ *  From the definitions    cli-args.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 35:0:10 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This source file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the gnutls-cli author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * This source file is copyrighted and licensed under the following terms:
+ *
+ *  Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *  
+PFX>gnutls-cli is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  gnutls-cli is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#define OPTION_CODE_COMPILE 1
+#include "cli-args.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+extern FILE * option_usage_fp;
+
+/* TRANSLATORS: choose the translation for option names wisely because you
+                cannot ever change your mind. */
+static char const zCopyright[278] =
+"gnutls-cli 3.0.11\n\
+Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.\n\
+This is free software. It is licensed for use, modification and\n\
+redistribution under the terms of the\n\
+GNU General Public License, version 3 or later\n\
+    <http://gnu.org/licenses/gpl.html>\n";
+static char const zLicenseDescrip[609] =
+"gnutls-cli is free software: you can redistribute it and/or modify it\n\
+under the terms of the GNU General Public License as published by the\n\
+Free Software Foundation, either version 3 of the License, or (at your\n\
+option) any later version.\n\n\
+gnutls-cli is distributed in the hope that it will be useful, but WITHOUT\n\
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n\
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n\
+for more details.\n\n\
+You should have received a copy of the GNU General Public License along\n\
+with this program.  If not, see <http://www.gnu.org/licenses/>.\n";
+
+extern tUsageProc optionUsage;
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+/*
+ *  Debug option description:
+ */
+static char const zDebugText[] =
+        "Enable debugging";
+static char const zDebug_NAME[]              = "DEBUG";
+static char const zDebug_Name[]              = "debug";
+#define DEBUG_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+
+/*
+ *  Resume option description:
+ */
+static char const zResumeText[] =
+        "Connect, establish a session. Connect again and resume this session";
+static char const zResume_NAME[]             = "RESUME";
+static char const zResume_Name[]             = "resume";
+#define RESUME_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Rehandshake option description:
+ */
+static char const zRehandshakeText[] =
+        "Connect, establish a session and rehandshake immediately";
+static char const zRehandshake_NAME[]        = "REHANDSHAKE";
+static char const zRehandshake_Name[]        = "rehandshake";
+#define REHANDSHAKE_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Noticket option description:
+ */
+static char const zNoticketText[] =
+        "Don't accept session tickets";
+static char const zNoticket_NAME[]           = "NOTICKET";
+static char const zNoticket_Name[]           = "noticket";
+#define NOTICKET_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Starttls option description:
+ */
+static char const zStarttlsText[] =
+        "Connect, establish a plain session and start TLS when EOF or a SIGALRM is received";
+static char const zStarttls_NAME[]           = "STARTTLS";
+static char const zStarttls_Name[]           = "starttls";
+#define STARTTLS_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Udp option description:
+ */
+static char const zUdpText[] =
+        "Use DTLS (datagram TLS) over UDP";
+static char const zUdp_NAME[]                = "UDP";
+static char const zUdp_Name[]                = "udp";
+#define UDP_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Mtu option description:
+ */
+static char const zMtuText[] =
+        "Set MTU for datagram TLS";
+static char const zMtu_NAME[]                = "MTU";
+static char const zMtu_Name[]                = "mtu";
+#define MTU_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+
+/*
+ *  Crlf option description:
+ */
+static char const zCrlfText[] =
+        "Send CR LF instead of LF";
+static char const zCrlf_NAME[]               = "CRLF";
+static char const zCrlf_Name[]               = "crlf";
+#define CRLF_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  X509fmtder option description:
+ */
+static char const zX509fmtderText[] =
+        "Use DER format for certificates to read from";
+static char const zX509fmtder_NAME[]         = "X509FMTDER";
+static char const zX509fmtder_Name[]         = "x509fmtder";
+#define X509FMTDER_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Fingerprint option description:
+ */
+static char const zFingerprintText[] =
+        "Send the openpgp fingerprint, instead of the key";
+static char const zFingerprint_NAME[]        = "FINGERPRINT";
+static char const zFingerprint_Name[]        = "fingerprint";
+#define FINGERPRINT_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Disable_Extensions option description:
+ */
+static char const zDisable_ExtensionsText[] =
+        "Disable all the TLS extensions";
+static char const zDisable_Extensions_NAME[] = "DISABLE_EXTENSIONS";
+static char const zDisable_Extensions_Name[] = "disable-extensions";
+#define DISABLE_EXTENSIONS_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Print_Cert option description:
+ */
+static char const zPrint_CertText[] =
+        "Print peer's certificate in PEM format";
+static char const zPrint_Cert_NAME[]         = "PRINT_CERT";
+static char const zPrint_Cert_Name[]         = "print-cert";
+#define PRINT_CERT_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Recordsize option description:
+ */
+static char const zRecordsizeText[] =
+        "The maximum record size to advertize";
+static char const zRecordsize_NAME[]         = "RECORDSIZE";
+static char const zRecordsize_Name[]         = "recordsize";
+#define RECORDSIZE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+
+/*
+ *  Verbose option description:
+ */
+static char const zVerboseText[] =
+        "More verbose output";
+static char const zVerbose_NAME[]            = "VERBOSE";
+static char const zVerbose_Name[]            = "verbose";
+#define VERBOSE_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Priority option description:
+ */
+static char const zPriorityText[] =
+        "Priorities string";
+static char const zPriority_NAME[]           = "PRIORITY";
+static char const zPriority_Name[]           = "priority";
+#define PRIORITY_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  X509cafile option description:
+ */
+static char const zX509cafileText[] =
+        "Certificate file or PKCS #11 URL to use";
+static char const zX509cafile_NAME[]         = "X509CAFILE";
+static char const zX509cafile_Name[]         = "x509cafile";
+#define X509CAFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  X509crlfile option description:
+ */
+static char const zX509crlfileText[] =
+        "CRL file to use";
+static char const zX509crlfile_NAME[]        = "X509CRLFILE";
+static char const zX509crlfile_Name[]        = "x509crlfile";
+#define X509CRLFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Pgpkeyfile option description:
+ */
+static char const zPgpkeyfileText[] =
+        "PGP Key file to use";
+static char const zPgpkeyfile_NAME[]         = "PGPKEYFILE";
+static char const zPgpkeyfile_Name[]         = "pgpkeyfile";
+#define PGPKEYFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Pgpkeyring option description:
+ */
+static char const zPgpkeyringText[] =
+        "PGP Key ring file to use";
+static char const zPgpkeyring_NAME[]         = "PGPKEYRING";
+static char const zPgpkeyring_Name[]         = "pgpkeyring";
+#define PGPKEYRING_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Pgpcertfile option description:
+ */
+static char const zPgpcertfileText[] =
+        "PGP Public Key (certificate) file to use";
+static char const zPgpcertfile_NAME[]        = "PGPCERTFILE";
+static char const zPgpcertfile_Name[]        = "pgpcertfile";
+#define PGPCERTFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  X509keyfile option description:
+ */
+static char const zX509keyfileText[] =
+        "X.509 key file or PKCS #11 URL to use";
+static char const zX509keyfile_NAME[]        = "X509KEYFILE";
+static char const zX509keyfile_Name[]        = "x509keyfile";
+#define X509KEYFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  X509certfile option description:
+ */
+static char const zX509certfileText[] =
+        "X.509 Certificate file or PKCS #11 URL to use";
+static char const zX509certfile_NAME[]       = "X509CERTFILE";
+static char const zX509certfile_Name[]       = "x509certfile";
+#define X509CERTFILE_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Pgpsubkey option description:
+ */
+static char const zPgpsubkeyText[] =
+        "PGP subkey to use (hex or auto)";
+static char const zPgpsubkey_NAME[]          = "PGPSUBKEY";
+static char const zPgpsubkey_Name[]          = "pgpsubkey";
+#define PGPSUBKEY_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Srpusername option description:
+ */
+static char const zSrpusernameText[] =
+        "SRP username to use";
+static char const zSrpusername_NAME[]        = "SRPUSERNAME";
+static char const zSrpusername_Name[]        = "srpusername";
+#define SRPUSERNAME_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Srppasswd option description:
+ */
+static char const zSrppasswdText[] =
+        "SRP password to use";
+static char const zSrppasswd_NAME[]          = "SRPPASSWD";
+static char const zSrppasswd_Name[]          = "srppasswd";
+#define SRPPASSWD_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Pskusername option description:
+ */
+static char const zPskusernameText[] =
+        "PSK username to use";
+static char const zPskusername_NAME[]        = "PSKUSERNAME";
+static char const zPskusername_Name[]        = "pskusername";
+#define PSKUSERNAME_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Pskkey option description:
+ */
+static char const zPskkeyText[] =
+        "PSK key (in hex) to use";
+static char const zPskkey_NAME[]             = "PSKKEY";
+static char const zPskkey_Name[]             = "pskkey";
+#define PSKKEY_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Port option description:
+ */
+static char const zPortText[] =
+        "The port to connect to";
+static char const zPort_NAME[]               = "PORT";
+static char const zPort_Name[]               = "port";
+#define PORT_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Insecure option description:
+ */
+static char const zInsecureText[] =
+        "Don't abort program if server certificate can't be validated";
+static char const zInsecure_NAME[]           = "INSECURE";
+static char const zInsecure_Name[]           = "insecure";
+#define INSECURE_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Benchmark_Ciphers option description:
+ */
+static char const zBenchmark_CiphersText[] =
+        "Benchmark individual ciphers";
+static char const zBenchmark_Ciphers_NAME[]  = "BENCHMARK_CIPHERS";
+static char const zBenchmark_Ciphers_Name[]  = "benchmark-ciphers";
+#define BENCHMARK_CIPHERS_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Benchmark_Soft_Ciphers option description:
+ */
+static char const zBenchmark_Soft_CiphersText[] =
+        "Benchmark individual software ciphers (no hw acceleration)";
+static char const zBenchmark_Soft_Ciphers_NAME[] = "BENCHMARK_SOFT_CIPHERS";
+static char const zBenchmark_Soft_Ciphers_Name[]= "benchmark-soft-ciphers";
+#define BENCHMARK_SOFT_CIPHERS_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Benchmark_Tls option description:
+ */
+static char const zBenchmark_TlsText[] =
+        "Benchmark ciphers and key exchange methods in TLS";
+static char const zBenchmark_Tls_NAME[]      = "BENCHMARK_TLS";
+static char const zBenchmark_Tls_Name[]      = "benchmark-tls";
+#define BENCHMARK_TLS_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  List option description:
+ */
+static char const zListText[] =
+        "Print a list of the supported algorithms and modes";
+static char const zList_NAME[]               = "LIST";
+static char const zList_Name[]               = "list";
+#define LIST_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Help/More_Help/Version option descriptions:
+ */
+static char const zHelpText[]          = "Display extended usage information and exit";
+static char const zHelp_Name[]         = "help";
+#ifdef HAVE_WORKING_FORK
+#define OPTST_MORE_HELP_FLAGS   (OPTST_IMM | OPTST_NO_INIT)
+static char const zMore_Help_Name[]    = "more-help";
+static char const zMore_HelpText[]     = "Extended usage information passed thru pager";
+#else
+#define OPTST_MORE_HELP_FLAGS   (OPTST_OMITTED | OPTST_NO_INIT)
+#define zMore_Help_Name   NULL
+#define zMore_HelpText    NULL
+#endif
+#ifdef NO_OPTIONAL_OPT_ARGS
+#  define OPTST_VERSION_FLAGS   OPTST_IMM | OPTST_NO_INIT
+#else
+#  define OPTST_VERSION_FLAGS   OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
+                                OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT
+#endif
+
+static char const zVersionText[]       = "Output version information and exit";
+static char const zVersion_Name[]      = "version";
+/*
+ *  Declare option callback procedures
+ */
+extern tOptProc
+    optionBooleanVal,    optionNestedVal,     optionNumericVal,
+    optionPagedUsage,    optionPrintVersion,  optionResetOpt,
+    optionStackArg,      optionTimeDate,      optionTimeVal,
+    optionUnstackArg,    optionVersionStderr;
+static tOptProc
+    doOptDebug,        doOptMtu,          doOptPgpcertfile,
+    doOptPgpkeyfile,   doOptPgpkeyring,   doOptRecordsize,
+    doOptX509cafile,   doOptX509certfile, doOptX509crlfile,
+    doOptX509keyfile,  doUsageOpt;
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Gnutls_Cli Option Descriptions.
+ */
+static tOptDesc optDesc[OPTION_CT] = {
+  {  /* entry idx, value */ 0, VALUE_OPT_DEBUG,
+     /* equiv idx, value */ 0, VALUE_OPT_DEBUG,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ DEBUG_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptDebug,
+     /* desc, NAME, name */ zDebugText, zDebug_NAME, zDebug_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 1, VALUE_OPT_RESUME,
+     /* equiv idx, value */ 1, VALUE_OPT_RESUME,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ RESUME_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zResumeText, zResume_NAME, zResume_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 2, VALUE_OPT_REHANDSHAKE,
+     /* equiv idx, value */ 2, VALUE_OPT_REHANDSHAKE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ REHANDSHAKE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zRehandshakeText, zRehandshake_NAME, zRehandshake_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 3, VALUE_OPT_NOTICKET,
+     /* equiv idx, value */ 3, VALUE_OPT_NOTICKET,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ NOTICKET_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zNoticketText, zNoticket_NAME, zNoticket_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 4, VALUE_OPT_STARTTLS,
+     /* equiv idx, value */ 4, VALUE_OPT_STARTTLS,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ STARTTLS_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zStarttlsText, zStarttls_NAME, zStarttls_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 5, VALUE_OPT_UDP,
+     /* equiv idx, value */ 5, VALUE_OPT_UDP,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ UDP_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zUdpText, zUdp_NAME, zUdp_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 6, VALUE_OPT_MTU,
+     /* equiv idx, value */ 6, VALUE_OPT_MTU,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ MTU_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptMtu,
+     /* desc, NAME, name */ zMtuText, zMtu_NAME, zMtu_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 7, VALUE_OPT_CRLF,
+     /* equiv idx, value */ 7, VALUE_OPT_CRLF,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ CRLF_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zCrlfText, zCrlf_NAME, zCrlf_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 8, VALUE_OPT_X509FMTDER,
+     /* equiv idx, value */ 8, VALUE_OPT_X509FMTDER,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ X509FMTDER_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zX509fmtderText, zX509fmtder_NAME, zX509fmtder_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 9, VALUE_OPT_FINGERPRINT,
+     /* equiv idx, value */ 9, VALUE_OPT_FINGERPRINT,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ FINGERPRINT_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zFingerprintText, zFingerprint_NAME, zFingerprint_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 10, VALUE_OPT_DISABLE_EXTENSIONS,
+     /* equiv idx, value */ 10, VALUE_OPT_DISABLE_EXTENSIONS,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ DISABLE_EXTENSIONS_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zDisable_ExtensionsText, zDisable_Extensions_NAME, zDisable_Extensions_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 11, VALUE_OPT_PRINT_CERT,
+     /* equiv idx, value */ 11, VALUE_OPT_PRINT_CERT,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PRINT_CERT_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPrint_CertText, zPrint_Cert_NAME, zPrint_Cert_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 12, VALUE_OPT_RECORDSIZE,
+     /* equiv idx, value */ 12, VALUE_OPT_RECORDSIZE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ RECORDSIZE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptRecordsize,
+     /* desc, NAME, name */ zRecordsizeText, zRecordsize_NAME, zRecordsize_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 13, VALUE_OPT_VERBOSE,
+     /* equiv idx, value */ 13, VALUE_OPT_VERBOSE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, NOLIMIT, 0,
+     /* opt state flags  */ VERBOSE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zVerboseText, zVerbose_NAME, zVerbose_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 14, VALUE_OPT_PRIORITY,
+     /* equiv idx, value */ 14, VALUE_OPT_PRIORITY,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PRIORITY_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPriorityText, zPriority_NAME, zPriority_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 15, VALUE_OPT_X509CAFILE,
+     /* equiv idx, value */ 15, VALUE_OPT_X509CAFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ X509CAFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptX509cafile,
+     /* desc, NAME, name */ zX509cafileText, zX509cafile_NAME, zX509cafile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 16, VALUE_OPT_X509CRLFILE,
+     /* equiv idx, value */ 16, VALUE_OPT_X509CRLFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ X509CRLFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptX509crlfile,
+     /* desc, NAME, name */ zX509crlfileText, zX509crlfile_NAME, zX509crlfile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 17, VALUE_OPT_PGPKEYFILE,
+     /* equiv idx, value */ 17, VALUE_OPT_PGPKEYFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PGPKEYFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptPgpkeyfile,
+     /* desc, NAME, name */ zPgpkeyfileText, zPgpkeyfile_NAME, zPgpkeyfile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 18, VALUE_OPT_PGPKEYRING,
+     /* equiv idx, value */ 18, VALUE_OPT_PGPKEYRING,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PGPKEYRING_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptPgpkeyring,
+     /* desc, NAME, name */ zPgpkeyringText, zPgpkeyring_NAME, zPgpkeyring_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 19, VALUE_OPT_PGPCERTFILE,
+     /* equiv idx, value */ 19, VALUE_OPT_PGPCERTFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PGPCERTFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptPgpcertfile,
+     /* desc, NAME, name */ zPgpcertfileText, zPgpcertfile_NAME, zPgpcertfile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 20, VALUE_OPT_X509KEYFILE,
+     /* equiv idx, value */ 20, VALUE_OPT_X509KEYFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ X509KEYFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptX509keyfile,
+     /* desc, NAME, name */ zX509keyfileText, zX509keyfile_NAME, zX509keyfile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 21, VALUE_OPT_X509CERTFILE,
+     /* equiv idx, value */ 21, VALUE_OPT_X509CERTFILE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ X509CERTFILE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptX509certfile,
+     /* desc, NAME, name */ zX509certfileText, zX509certfile_NAME, zX509certfile_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 22, VALUE_OPT_PGPSUBKEY,
+     /* equiv idx, value */ 22, VALUE_OPT_PGPSUBKEY,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PGPSUBKEY_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPgpsubkeyText, zPgpsubkey_NAME, zPgpsubkey_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 23, VALUE_OPT_SRPUSERNAME,
+     /* equiv idx, value */ 23, VALUE_OPT_SRPUSERNAME,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ SRPUSERNAME_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zSrpusernameText, zSrpusername_NAME, zSrpusername_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 24, VALUE_OPT_SRPPASSWD,
+     /* equiv idx, value */ 24, VALUE_OPT_SRPPASSWD,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ SRPPASSWD_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zSrppasswdText, zSrppasswd_NAME, zSrppasswd_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 25, VALUE_OPT_PSKUSERNAME,
+     /* equiv idx, value */ 25, VALUE_OPT_PSKUSERNAME,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PSKUSERNAME_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPskusernameText, zPskusername_NAME, zPskusername_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 26, VALUE_OPT_PSKKEY,
+     /* equiv idx, value */ 26, VALUE_OPT_PSKKEY,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PSKKEY_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPskkeyText, zPskkey_NAME, zPskkey_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 27, VALUE_OPT_PORT,
+     /* equiv idx, value */ 27, VALUE_OPT_PORT,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PORT_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPortText, zPort_NAME, zPort_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 28, VALUE_OPT_INSECURE,
+     /* equiv idx, value */ 28, VALUE_OPT_INSECURE,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ INSECURE_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zInsecureText, zInsecure_NAME, zInsecure_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 29, VALUE_OPT_BENCHMARK_CIPHERS,
+     /* equiv idx, value */ 29, VALUE_OPT_BENCHMARK_CIPHERS,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ BENCHMARK_CIPHERS_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zBenchmark_CiphersText, zBenchmark_Ciphers_NAME, zBenchmark_Ciphers_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 30, VALUE_OPT_BENCHMARK_SOFT_CIPHERS,
+     /* equiv idx, value */ 30, VALUE_OPT_BENCHMARK_SOFT_CIPHERS,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ BENCHMARK_SOFT_CIPHERS_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zBenchmark_Soft_CiphersText, zBenchmark_Soft_Ciphers_NAME, zBenchmark_Soft_Ciphers_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 31, VALUE_OPT_BENCHMARK_TLS,
+     /* equiv idx, value */ 31, VALUE_OPT_BENCHMARK_TLS,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ BENCHMARK_TLS_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zBenchmark_TlsText, zBenchmark_Tls_NAME, zBenchmark_Tls_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 32, VALUE_OPT_LIST,
+     /* equiv idx, value */ 32, VALUE_OPT_LIST,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ LIST_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zListText, zList_NAME, zList_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ INDEX_OPT_VERSION, VALUE_OPT_VERSION,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_VERSION_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ optionPrintVersion,
+     /* desc, NAME, name */ zVersionText, NULL, zVersion_Name,
+     /* disablement strs */ NULL, NULL },
+
+
+
+  {  /* entry idx, value */ INDEX_OPT_HELP, VALUE_OPT_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_IMM | OPTST_NO_INIT, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doUsageOpt,
+     /* desc, NAME, name */ zHelpText, NULL, zHelp_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ INDEX_OPT_MORE_HELP, VALUE_OPT_MORE_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_MORE_HELP_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL,  NULL,
+     /* option proc      */ optionPagedUsage,
+     /* desc, NAME, name */ zMore_HelpText, NULL, zMore_Help_Name,
+     /* disablement strs */ NULL, NULL }
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Gnutls_Cli Option Environment
+ */
+static char const zPROGNAME[11] = "GNUTLS_CLI";
+static char const zUsageTitle[100] =
+"gnutls-cli - GnuTLS client - Ver. 3.0.11\n\
+USAGE:  %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \n";
+#define zRcName     NULL
+#define apzHomeList NULL
+
+static char const zBugsAddr[19]    = "bug-gnutls@gnu.org";
+#define zExplain NULL
+static char const zDetail[195] = "\n\
+Simple client program to set up a TLS connection to some other computer.\n\
+It sets up a TLS connection and forwards data from the standard input\n\
+to the secured socket and vice versa.\n";
+static char const zFullVersion[] = GNUTLS_CLI_FULL_VERSION;
+/* extracted from optcode.tlib near line 515 */
+
+#if defined(ENABLE_NLS)
+# define OPTPROC_BASE OPTPROC_TRANSLATE
+  static tOptionXlateProc translate_option_strings;
+#else
+# define OPTPROC_BASE OPTPROC_NONE
+# define translate_option_strings NULL
+#endif /* ENABLE_NLS */
+
+
+#define gnutls_cli_full_usage NULL
+static char const gnutls_cli_short_usage[] =
+       "Usage: gnutls-cli [options] hostname\n\
+gnutls-cli --help for usage instructions.\n";
+
+#ifndef  PKGDATADIR
+# define PKGDATADIR ""
+#endif
+
+#ifndef  WITH_PACKAGER
+# define gnutls_cli_packager_info NULL
+#else
+static char const gnutls_cli_packager_info[] =
+    "Packaged by " WITH_PACKAGER
+
+# ifdef WITH_PACKAGER_VERSION
+        " ("WITH_PACKAGER_VERSION")"
+# endif
+
+# ifdef WITH_PACKAGER_BUG_REPORTS
+    "\nReport gnutls_cli bugs to " WITH_PACKAGER_BUG_REPORTS
+# endif
+    "\n";
+#endif
+
+tOptions gnutls_cliOptions = {
+    OPTIONS_STRUCT_VERSION,
+    0, NULL,                    /* original argc + argv    */
+    ( OPTPROC_BASE
+    + OPTPROC_ERRSTOP
+    + OPTPROC_SHORTOPT
+    + OPTPROC_LONGOPT
+    + OPTPROC_NO_REQ_OPT
+    + OPTPROC_ARGS_REQ
+    + OPTPROC_REORDER
+    + OPTPROC_GNUUSAGE
+    + OPTPROC_MISUSE ),
+    0, NULL,                    /* current option index, current option */
+    NULL,         NULL,         zPROGNAME,
+    zRcName,      zCopyright,   zLicenseDescrip,
+    zFullVersion, apzHomeList,  zUsageTitle,
+    zExplain,     zDetail,      optDesc,
+    zBugsAddr,                  /* address to send bugs to */
+    NULL, NULL,                 /* extensions/saved state  */
+    optionUsage, /* usage procedure */
+    translate_option_strings,   /* translation procedure */
+    /*
+     *  Indexes to special options
+     */
+    { INDEX_OPT_MORE_HELP, /* more-help option index */
+      NO_EQUIVALENT, /* save option index */
+      NO_EQUIVALENT, /* '-#' option index */
+      NO_EQUIVALENT /* index of default opt */
+    },
+    36 /* full option count */, 33 /* user option count */,
+    gnutls_cli_full_usage, gnutls_cli_short_usage,
+    NULL, NULL,
+    PKGDATADIR, gnutls_cli_packager_info
+};
+
+/*
+ *  Create the static procedure(s) declared above.
+ */
+static void
+doUsageOpt(tOptions * pOptions, tOptDesc * pOptDesc)
+{
+    (void)pOptions;
+    USAGE(GNUTLS_CLI_EXIT_SUCCESS);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the debug option.
+ */
+static void
+doOptDebug(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static const struct {long const rmin, rmax;} rng[1] = {
+        { 0 ,  9999 } };
+    int  ix;
+
+    if (pOptions <= OPTPROC_EMIT_LIMIT)
+        goto emit_ranges;
+    optionNumericVal(pOptions, pOptDesc);
+
+    for (ix = 0; ix < 1; ix++) {
+        if (pOptDesc->optArg.argInt < rng[ix].rmin)
+            continue;  /* ranges need not be ordered. */
+        if (pOptDesc->optArg.argInt == rng[ix].rmin)
+            return;
+        if (rng[ix].rmax == LONG_MIN)
+            continue;
+        if (pOptDesc->optArg.argInt <= rng[ix].rmax)
+            return;
+    }
+
+    option_usage_fp = stderr;
+
+emit_ranges:
+
+    optionShowRange(pOptions, pOptDesc, (void *)rng, 1);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the mtu option.
+ */
+static void
+doOptMtu(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static const struct {long const rmin, rmax;} rng[1] = {
+        { 0, 17000 } };
+    int  ix;
+
+    if (pOptions <= OPTPROC_EMIT_LIMIT)
+        goto emit_ranges;
+    optionNumericVal(pOptions, pOptDesc);
+
+    for (ix = 0; ix < 1; ix++) {
+        if (pOptDesc->optArg.argInt < rng[ix].rmin)
+            continue;  /* ranges need not be ordered. */
+        if (pOptDesc->optArg.argInt == rng[ix].rmin)
+            return;
+        if (rng[ix].rmax == LONG_MIN)
+            continue;
+        if (pOptDesc->optArg.argInt <= rng[ix].rmax)
+            return;
+    }
+
+    option_usage_fp = stderr;
+
+emit_ranges:
+
+    optionShowRange(pOptions, pOptDesc, (void *)rng, 1);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the recordsize option.
+ */
+static void
+doOptRecordsize(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static const struct {long const rmin, rmax;} rng[1] = {
+        { 0, 4096 } };
+    int  ix;
+
+    if (pOptions <= OPTPROC_EMIT_LIMIT)
+        goto emit_ranges;
+    optionNumericVal(pOptions, pOptDesc);
+
+    for (ix = 0; ix < 1; ix++) {
+        if (pOptDesc->optArg.argInt < rng[ix].rmin)
+            continue;  /* ranges need not be ordered. */
+        if (pOptDesc->optArg.argInt == rng[ix].rmin)
+            return;
+        if (rng[ix].rmax == LONG_MIN)
+            continue;
+        if (pOptDesc->optArg.argInt <= rng[ix].rmax)
+            return;
+    }
+
+    option_usage_fp = stderr;
+
+emit_ranges:
+
+    optionShowRange(pOptions, pOptDesc, (void *)rng, 1);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the x509cafile option.
+ */
+static void
+doOptX509cafile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the x509crlfile option.
+ */
+static void
+doOptX509crlfile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the pgpkeyfile option.
+ */
+static void
+doOptPgpkeyfile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the pgpkeyring option.
+ */
+static void
+doOptPgpkeyring(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the pgpcertfile option.
+ */
+static void
+doOptPgpcertfile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the x509keyfile option.
+ */
+static void
+doOptX509keyfile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the x509certfile option.
+ */
+static void
+doOptX509certfile(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+/* extracted from optcode.tlib near line 666 */
+
+#if ENABLE_NLS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <autoopts/usage-txt.h>
+
+static char* AO_gettext(char const* pz);
+static void  coerce_it(void** s);
+
+static char*
+AO_gettext(char const* pz)
+{
+    char* pzRes;
+    if (pz == NULL)
+        return NULL;
+    pzRes = _(pz);
+    if (pzRes == pz)
+        return pzRes;
+    pzRes = strdup(pzRes);
+    if (pzRes == NULL) {
+        fputs(_("No memory for duping translated strings\n"), stderr);
+        exit(GNUTLS_CLI_EXIT_FAILURE);
+    }
+    return pzRes;
+}
+
+static void coerce_it(void** s) { *s = AO_gettext(*s);
+}
+
+/*
+ *  This invokes the translation code (e.g. gettext(3)).
+ */
+static void
+translate_option_strings(void)
+{
+    tOptions * const pOpt = &gnutls_cliOptions;
+
+    /*
+     *  Guard against re-translation.  It won't work.  The strings will have
+     *  been changed by the first pass through this code.  One shot only.
+     */
+    if (option_usage_text.field_ct != 0) {
+        /*
+         *  Do the translations.  The first pointer follows the field count
+         *  field.  The field count field is the size of a pointer.
+         */
+        tOptDesc * pOD = pOpt->pOptDesc;
+        char **    ppz = (char**)(void*)&(option_usage_text);
+        int        ix  = option_usage_text.field_ct;
+
+        do {
+            ppz++;
+            *ppz = AO_gettext(*ppz);
+        } while (--ix > 0);
+
+        coerce_it((void*)&(pOpt->pzCopyright));
+        coerce_it((void*)&(pOpt->pzCopyNotice));
+        coerce_it((void*)&(pOpt->pzFullVersion));
+        coerce_it((void*)&(pOpt->pzUsageTitle));
+        coerce_it((void*)&(pOpt->pzExplain));
+        coerce_it((void*)&(pOpt->pzDetail));
+        coerce_it((void*)&(pOpt->pzPackager));
+        coerce_it((void*)&(pOpt->pzShortUsage));
+        option_usage_text.field_ct = 0;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++)
+            coerce_it((void*)&(pOD->pzText));
+    }
+
+    if ((pOpt->fOptSet & OPTPROC_NXLAT_OPT_CFG) == 0) {
+        tOptDesc * pOD = pOpt->pOptDesc;
+        int        ix;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++) {
+            coerce_it((void*)&(pOD->pz_Name));
+            coerce_it((void*)&(pOD->pz_DisableName));
+            coerce_it((void*)&(pOD->pz_DisablePfx));
+        }
+        /* prevent re-translation */
+        gnutls_cliOptions.fOptSet |= OPTPROC_NXLAT_OPT_CFG | OPTPROC_NXLAT_OPT;
+    }
+}
+
+#endif /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+/* cli-args.c ends here */
diff --git a/src/cli-args.def.in b/src/cli-args.def.in
new file mode 100644 (file)
index 0000000..ed50025
--- /dev/null
@@ -0,0 +1,276 @@
+AutoGen Definitions options;
+prog-name     = gnutls-cli;
+prog-title    = "GnuTLS client";
+prog-desc     = "Simple client program to set up a TLS connection.";
+short-usage   = "Usage: gnutls-cli [options] hostname\ngnutls-cli --help for usage instructions.\n";
+prog-group    = "GnuTLS";
+detail        = "Simple client program to set up a TLS connection to some other computer. 
+It sets up a TLS connection and forwards data from the standard input to the secured socket and vice versa.";
+gnu-usage;
+no-misuse-usage;
+disable-save;
+reorder-args;
+argument;
+long-opts;
+config-header = 'config.h';
+export = '#include <gettext.h>';
+
+copyright = {
+    date  = "2000-2012";
+    owner = "Free Software Foundation";
+    author = "Nikos Mavrogiannopoulos and Simon Josefsson";
+    eaddr  = "bug-gnutls@gnu.org";
+    type  = gpl;
+};
+version = "@VERSION@";
+
+flag = {
+    name      = debug;
+    value     = d;
+    arg-type  = number;
+    arg-range = "0 -> 9999";
+    descrip   = "Enable debugging";
+    doc       = "";
+};
+
+flag = {
+    name      = resume;
+    value     = r;
+    descrip   = "Connect, establish a session. Connect again and resume this session";
+    doc       = "";
+};
+
+flag = {
+    name      = rehandshake;
+    value     = e;
+    descrip   = "Connect, establish a session and rehandshake immediately";
+    doc       = "";
+};
+
+flag = {
+    name      = noticket;
+    descrip   = "Don't accept session tickets";
+    doc      = "";
+};
+
+flag = {
+    name      = starttls;
+    value     = s;
+    descrip   = "Connect, establish a plain session and start TLS when EOF or a SIGALRM is received";
+    doc      = "";
+};
+
+flag = {
+    name      = udp;
+    value     = u;
+    descrip   = "Use DTLS (datagram TLS) over UDP";
+    doc      = "";
+};
+
+flag = {
+    name      = mtu;
+    arg-type  = number;
+    arg-range = "0->17000";
+    descrip   = "Set MTU for datagram TLS";
+    doc      = "";
+};
+
+flag = {
+    name      = crlf;
+    descrip   = "Send CR LF instead of LF";
+    doc      = "";
+};
+
+flag = {
+    name      = x509fmtder;
+    descrip   = "Use DER format for certificates to read from";
+    doc      = "";
+};
+
+flag = {
+    name      = fingerprint;
+    value     = f;
+    descrip   = "Send the openpgp fingerprint, instead of the key";
+    doc      = "";
+};
+
+flag = {
+    name      = disable-extensions;
+    descrip   = "Disable all the TLS extensions";
+    doc      = "";
+};
+
+flag = {
+    name      = print-cert;
+    descrip   = "Print peer's certificate in PEM format";
+    doc      = "";
+};
+
+flag = {
+    name      = recordsize;
+    arg-type  = number;
+    arg-range = "0->4096";
+    descrip   = "The maximum record size to advertize";
+    doc      = "";
+};
+
+flag = {
+    name      = verbose;
+    value     = V;
+    max       = NOLIMIT;
+    descrip   = "More verbose output";
+    doc      = "";
+};
+
+flag = {
+    name      = priority;
+    arg-type  = string;
+    descrip   = "Priorities string";
+    doc      = "TLS algorithms and protocols to enable. You can
+use predefined sets of ciphersuites such as PERFORMANCE,
+NORMAL, SECURE128, SECURE256.
+
+Check  the  GnuTLS  manual  on  section  ``Priority strings'' for more
+information on allowed keywords";
+};
+
+flag = {
+    name      = x509cafile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "Certificate file or PKCS #11 URL to use";
+    doc      = "";
+};
+
+flag = {
+    name      = x509crlfile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "CRL file to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pgpkeyfile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "PGP Key file to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pgpkeyring;
+    arg-type  = file;
+    file-exists;
+    descrip   = "PGP Key ring file to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pgpcertfile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "PGP Public Key (certificate) file to use";
+    doc      = "";
+};
+
+flag = {
+    name      = x509keyfile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "X.509 key file or PKCS #11 URL to use";
+    doc      = "";
+};
+
+flag = {
+    name      = x509certfile;
+    arg-type  = file;
+    file-exists;
+    descrip   = "X.509 Certificate file or PKCS #11 URL to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pgpsubkey;
+    arg-type  = string;
+    descrip   = "PGP subkey to use (hex or auto)";
+    doc      = "";
+};
+
+flag = {
+    name      = srpusername;
+    arg-type  = string;
+    descrip   = "SRP username to use";
+    doc      = "";
+};
+
+flag = {
+    name      = srppasswd;
+    arg-type  = string;
+    descrip   = "SRP password to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pskusername;
+    arg-type  = string;
+    descrip   = "PSK username to use";
+    doc      = "";
+};
+
+flag = {
+    name      = pskkey;
+    arg-type  = string;
+    descrip   = "PSK key (in hex) to use";
+    doc      = "";
+};
+
+flag = {
+    name      = port;
+    value     = p;
+    arg-type  = string;
+    descrip   = "The port to connect to";
+    doc      = "";
+};
+
+flag = {
+    name      = insecure;
+    descrip   = "Don't abort program if server certificate can't be validated";
+    doc      = "";
+};
+
+flag = {
+    name      = benchmark-ciphers;
+    descrip   = "Benchmark individual ciphers";
+    doc      = "";
+};
+
+flag = {
+    name      = benchmark-soft-ciphers;
+    descrip   = "Benchmark individual software ciphers (no hw acceleration)";
+    doc      = "";
+};
+
+flag = {
+    name      = benchmark-tls;
+    descrip   = "Benchmark ciphers and key exchange methods in TLS";
+    doc      = "";
+};
+
+flag = {
+    name      = list;
+    value     = l;
+    arg-type  = string;
+    descrip   = "Print a list of the supported algorithms and modes";
+    doc      = "Print a list of the supported algorithms and modes. If a priority string is given then only the enabled ciphersuites are shown.";
+};
+
+       
+
+doc-section = {
+  ds-type   = 'SEE ALSO'; // or anything else
+  ds-format = 'man';      // or texi or mdoc format
+  ds-text   = <<-_EOText_
+gnutls-cli-debug(1), gnutls-serv(1)
+_EOText_;
+};
diff --git a/src/cli-args.h b/src/cli-args.h
new file mode 100644 (file)
index 0000000..d789e3b
--- /dev/null
@@ -0,0 +1,250 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (cli-args.h)
+ *  
+ *  It has been AutoGen-ed  January 19, 2012 at 09:24:21 PM by AutoGen 5.12
+ *  From the definitions    cli-args.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 35:0:10 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This header file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the gnutls-cli author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * This source file is copyrighted and licensed under the following terms:
+ *
+ *  Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *  
+PFX>gnutls-cli is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  gnutls-cli is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ *  This file contains the programmatic interface to the Automated
+ *  Options generated for the gnutls-cli program.
+ *  These macros are documented in the AutoGen info file in the
+ *  "AutoOpts" chapter.  Please refer to that doc for usage help.
+ */
+#ifndef AUTOOPTS_CLI_ARGS_H_GUARD
+#define AUTOOPTS_CLI_ARGS_H_GUARD 1
+#include "config.h"
+#include <autoopts/options.h>
+
+/*
+ *  Ensure that the library used for compiling this generated header is at
+ *  least as new as the version current when the header template was released
+ *  (not counting patch version increments).  Also ensure that the oldest
+ *  tolerable version is at least as old as what was current when the header
+ *  template was released.
+ */
+#define AO_TEMPLATE_VERSION 143360
+#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
+ || (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
+# error option template version mismatches autoopts/options.h header
+  Choke Me.
+#endif
+
+/*
+ *  Enumeration of each option:
+ */
+typedef enum {
+    INDEX_OPT_DEBUG                   =  0,
+    INDEX_OPT_RESUME                  =  1,
+    INDEX_OPT_REHANDSHAKE             =  2,
+    INDEX_OPT_NOTICKET                =  3,
+    INDEX_OPT_STARTTLS                =  4,
+    INDEX_OPT_UDP                     =  5,
+    INDEX_OPT_MTU                     =  6,
+    INDEX_OPT_CRLF                    =  7,
+    INDEX_OPT_X509FMTDER              =  8,
+    INDEX_OPT_FINGERPRINT             =  9,
+    INDEX_OPT_DISABLE_EXTENSIONS      = 10,
+    INDEX_OPT_PRINT_CERT              = 11,
+    INDEX_OPT_RECORDSIZE              = 12,
+    INDEX_OPT_VERBOSE                 = 13,
+    INDEX_OPT_PRIORITY                = 14,
+    INDEX_OPT_X509CAFILE              = 15,
+    INDEX_OPT_X509CRLFILE             = 16,
+    INDEX_OPT_PGPKEYFILE              = 17,
+    INDEX_OPT_PGPKEYRING              = 18,
+    INDEX_OPT_PGPCERTFILE             = 19,
+    INDEX_OPT_X509KEYFILE             = 20,
+    INDEX_OPT_X509CERTFILE            = 21,
+    INDEX_OPT_PGPSUBKEY               = 22,
+    INDEX_OPT_SRPUSERNAME             = 23,
+    INDEX_OPT_SRPPASSWD               = 24,
+    INDEX_OPT_PSKUSERNAME             = 25,
+    INDEX_OPT_PSKKEY                  = 26,
+    INDEX_OPT_PORT                    = 27,
+    INDEX_OPT_INSECURE                = 28,
+    INDEX_OPT_BENCHMARK_CIPHERS       = 29,
+    INDEX_OPT_BENCHMARK_SOFT_CIPHERS  = 30,
+    INDEX_OPT_BENCHMARK_TLS           = 31,
+    INDEX_OPT_LIST                    = 32,
+    INDEX_OPT_VERSION                 = 33,
+    INDEX_OPT_HELP                    = 34,
+    INDEX_OPT_MORE_HELP               = 35
+} teOptIndex;
+
+#define OPTION_CT    36
+#define GNUTLS_CLI_VERSION       "3.0.11"
+#define GNUTLS_CLI_FULL_VERSION  "gnutls-cli 3.0.11"
+
+/*
+ *  Interface defines for all options.  Replace "n" with the UPPER_CASED
+ *  option name (as in the teOptIndex enumeration above).
+ *  e.g. HAVE_OPT(DEBUG)
+ */
+#define         DESC(n) (gnutls_cliOptions.pOptDesc[INDEX_OPT_## n])
+#define     HAVE_OPT(n) (! UNUSED_OPT(& DESC(n)))
+#define      OPT_ARG(n) (DESC(n).optArg.argString)
+#define    STATE_OPT(n) (DESC(n).fOptState & OPTST_SET_MASK)
+#define    COUNT_OPT(n) (DESC(n).optOccCt)
+#define    ISSEL_OPT(n) (SELECTED_OPT(&DESC(n)))
+#define ISUNUSED_OPT(n) (UNUSED_OPT(& DESC(n)))
+#define  ENABLED_OPT(n) (! DISABLED_OPT(& DESC(n)))
+#define  STACKCT_OPT(n) (((tArgList*)(DESC(n).optCookie))->useCt)
+#define STACKLST_OPT(n) (((tArgList*)(DESC(n).optCookie))->apzArgs)
+#define    CLEAR_OPT(n) STMTS( \
+                DESC(n).fOptState &= OPTST_PERSISTENT_MASK;   \
+                if ((DESC(n).fOptState & OPTST_INITENABLED) == 0) \
+                    DESC(n).fOptState |= OPTST_DISABLED; \
+                DESC(n).optCookie = NULL )
+
+/* * * * * *
+ *
+ *  Enumeration of gnutls-cli exit codes
+ */
+typedef enum {
+    GNUTLS_CLI_EXIT_SUCCESS = 0,
+    GNUTLS_CLI_EXIT_FAILURE = 1
+} gnutls_cli_exit_code_t;
+/* * * * * *
+ *
+ *  Interface defines for specific options.
+ */
+#define VALUE_OPT_DEBUG          'd'
+
+#define OPT_VALUE_DEBUG          (DESC(DEBUG).optArg.argInt)
+#define VALUE_OPT_RESUME         'r'
+#define VALUE_OPT_REHANDSHAKE    'e'
+#define VALUE_OPT_NOTICKET       3
+#define VALUE_OPT_STARTTLS       's'
+#define VALUE_OPT_UDP            'u'
+#define VALUE_OPT_MTU            6
+
+#define OPT_VALUE_MTU            (DESC(MTU).optArg.argInt)
+#define VALUE_OPT_CRLF           7
+#define VALUE_OPT_X509FMTDER     8
+#define VALUE_OPT_FINGERPRINT    'f'
+#define VALUE_OPT_DISABLE_EXTENSIONS 10
+#define VALUE_OPT_PRINT_CERT     11
+#define VALUE_OPT_RECORDSIZE     12
+
+#define OPT_VALUE_RECORDSIZE     (DESC(RECORDSIZE).optArg.argInt)
+#define VALUE_OPT_VERBOSE        'V'
+#define VALUE_OPT_PRIORITY       14
+#define VALUE_OPT_X509CAFILE     15
+#define VALUE_OPT_X509CRLFILE    16
+#define VALUE_OPT_PGPKEYFILE     17
+#define VALUE_OPT_PGPKEYRING     18
+#define VALUE_OPT_PGPCERTFILE    19
+#define VALUE_OPT_X509KEYFILE    20
+#define VALUE_OPT_X509CERTFILE   21
+#define VALUE_OPT_PGPSUBKEY      22
+#define VALUE_OPT_SRPUSERNAME    23
+#define VALUE_OPT_SRPPASSWD      24
+#define VALUE_OPT_PSKUSERNAME    25
+#define VALUE_OPT_PSKKEY         26
+#define VALUE_OPT_PORT           'p'
+#define VALUE_OPT_INSECURE       28
+#define VALUE_OPT_BENCHMARK_CIPHERS 29
+#define VALUE_OPT_BENCHMARK_SOFT_CIPHERS 30
+#define VALUE_OPT_BENCHMARK_TLS  31
+#define VALUE_OPT_LIST           'l'
+#define VALUE_OPT_HELP          '?'
+#define VALUE_OPT_MORE_HELP     '!'
+#define VALUE_OPT_VERSION       'v'
+/*
+ *  Interface defines not associated with particular options
+ */
+#define ERRSKIP_OPTERR  STMTS(gnutls_cliOptions.fOptSet &= ~OPTPROC_ERRSTOP)
+#define ERRSTOP_OPTERR  STMTS(gnutls_cliOptions.fOptSet |= OPTPROC_ERRSTOP)
+#define RESTART_OPT(n)  STMTS( \
+                gnutls_cliOptions.curOptIdx = (n); \
+                gnutls_cliOptions.pzCurOpt  = NULL)
+#define START_OPT       RESTART_OPT(1)
+#define USAGE(c)        (*gnutls_cliOptions.pUsageProc)(&gnutls_cliOptions, c)
+/* extracted from opthead.tlib near line 451 */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* * * * * *
+ *
+ *  Globals exported from the GnuTLS client option definitions
+ */
+#include <gettext.h>
+
+/* * * * * *
+ *
+ *  Declare the gnutls-cli option descriptor.
+ */
+extern tOptions gnutls_cliOptions;
+
+#if defined(ENABLE_NLS)
+# ifndef _
+#   include <stdio.h>
+static inline char* aoGetsText(char const* pz) {
+    if (pz == NULL) return NULL;
+    return (char*)gettext(pz);
+}
+#   define _(s)  aoGetsText(s)
+# endif /* _() */
+
+# define OPT_NO_XLAT_CFG_NAMES  STMTS(gnutls_cliOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT_CFG;)
+# define OPT_NO_XLAT_OPT_NAMES  STMTS(gnutls_cliOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG;)
+
+# define OPT_XLAT_CFG_NAMES     STMTS(gnutls_cliOptions.fOptSet &= \
+                                  ~(OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG);)
+# define OPT_XLAT_OPT_NAMES     STMTS(gnutls_cliOptions.fOptSet &= \
+                                  ~OPTPROC_NXLAT_OPT;)
+
+#else   /* ENABLE_NLS */
+# define OPT_NO_XLAT_CFG_NAMES
+# define OPT_NO_XLAT_OPT_NAMES
+
+# define OPT_XLAT_CFG_NAMES
+# define OPT_XLAT_OPT_NAMES
+
+# ifndef _
+#   define _(_s)  _s
+# endif
+#endif  /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif /* AUTOOPTS_CLI_ARGS_H_GUARD */
+/* cli-args.h ends here */
diff --git a/src/cli-debug-args.def.in b/src/cli-debug-args.def.in
new file mode 100644 (file)
index 0000000..1cae337
--- /dev/null
@@ -0,0 +1,60 @@
+AutoGen Definitions options;
+prog-name     = gnutls-cli-debug;
+prog-title    = "GnuTLS debug client";
+prog-desc     = "Simple client program to check TLS server capabilities.";
+short-usage   = "Usage: gnutls-cli-debug [options] hostname\ngnutls-cli --help for usage instructions.\n";
+prog-group    = "GnuTLS";
+detail        = "TLS debug client. It sets up multiple TLS connections to 
+a server and queries its capabilities. Can be used to check for servers with
+special needs or bugs.";
+gnu-usage;
+no-misuse-usage;
+disable-save;
+reorder-args;
+argument;
+long-opts;
+config-header = 'config.h';
+export = '#include <gettext.h>';
+
+copyright = {
+    date  = "2000-2012";
+    owner = "Free Software Foundation";
+    author = "Nikos Mavrogiannopoulos and Simon Josefsson";
+    eaddr  = "bug-gnutls@gnu.org";
+    type  = gpl;
+};
+version = "@VERSION@";
+
+flag = {
+    name      = debug;
+    value     = d;
+    arg-type  = number;
+    arg-range = "0 -> 9999";
+    descrip   = "Enable debugging";
+    doc       = "";
+};
+
+flag = {
+    name      = verbose;
+    value     = V;
+    max       = NOLIMIT;
+    descrip   = "More verbose output";
+    doc      = "";
+};
+
+flag = {
+    name      = port;
+    value     = p;
+    arg-type  = number;
+    arg-range = "0 -> 65536";
+    descrip   = "The port to connect to";
+    doc      = "";
+};
+
+doc-section = {
+  ds-type   = 'SEE ALSO'; // or anything else
+  ds-format = 'man';      // or texi or mdoc format
+  ds-text   = <<-_EOText_
+gnutls-cli(1), gnutls-serv(1)
+_EOText_;
+};
index 40610b6e78e2da1b59feedb10335192ac65f0dd6..7ed6dcc7ddacbaf453d40f67d2376452045b4190 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
 #include "sockets.h"
 
 #include "common.h"
-#include "cli-gaa.h"
+
+#include "gettext.h"
+#include "cli-args.h"
 
 #define MAX_BUF 4096
 
 /* global stuff here */
 int resume, starttls, insecure, rehandshake, udp, mtu;
 const char *hostname = NULL;
-char *service;
+const char *service = NULL;
 int record_max_size;
 int fingerprint;
 int crlf;
 int verbose = 0;
 extern int print_cert;
 
-char *srp_passwd = NULL;
-char *srp_username;
-char *pgp_keyfile;
-char *pgp_certfile;
-char *pgp_keyring;
-char *x509_keyfile;
-char *x509_certfile;
-char *x509_cafile;
-char *x509_crlfile = NULL;
+const char *srp_passwd = NULL;
+const char *srp_username = NULL;
+const char *pgp_keyfile = NULL;
+const char *pgp_certfile = NULL;
+const char *pgp_keyring = NULL;
+const char *x509_keyfile = NULL;
+const char *x509_certfile = NULL;
+const char *x509_cafile = NULL;
+const char *x509_crlfile = NULL;
 static int x509ctype;
 static int disable_extensions;
 
-char *psk_username = NULL;
+const char *psk_username = NULL;
 gnutls_datum_t psk_key = { NULL, 0 };
 
 static gnutls_srp_client_credentials_t srp_cred;
@@ -86,8 +88,6 @@ static gnutls_psk_client_credentials_t psk_cred;
 static gnutls_anon_client_credentials_t anon_cred;
 static gnutls_certificate_credentials_t xcred;
 
-static gaainfo info;
-
 /* end of global stuff */
 
 /* prototypes */
@@ -322,9 +322,9 @@ load_keys (void)
 
 
 #ifdef ENABLE_OPENPGP
-  if (info.pgp_subkey != NULL)
+  if (HAVE_OPT(PGPSUBKEY))
     {
-      get_keyid (keyid, info.pgp_subkey);
+      get_keyid (keyid, OPT_ARG(PGPSUBKEY));
     }
 
   if (pgp_certfile != NULL && pgp_keyfile != NULL)
@@ -341,7 +341,7 @@ load_keys (void)
       gnutls_openpgp_crt_init (&tmp_pgp_crt);
 
       ret =
-        gnutls_pcert_import_openpgp_raw (&pgp_crt, &data, GNUTLS_OPENPGP_FMT_BASE64, info.pgp_subkey!=NULL?keyid:NULL, 0);
+        gnutls_pcert_import_openpgp_raw (&pgp_crt, &data, GNUTLS_OPENPGP_FMT_BASE64, HAVE_OPT(PGPSUBKEY)?keyid:NULL, 0);
       if (ret < 0)
         {
           fprintf (stderr,
@@ -407,7 +407,7 @@ load_keys (void)
               exit (1);
             }
 
-          if (info.pgp_subkey != NULL)
+          if (HAVE_OPT(PGPSUBKEY))
             {
               ret =
                 gnutls_openpgp_privkey_set_preferred_key_id (tmp_pgp_key, keyid);
@@ -415,7 +415,7 @@ load_keys (void)
                 {
                   fprintf (stderr,
                       "*** Error setting preferred sub key id (%s): %s\n",
-                      info.pgp_subkey, gnutls_strerror (ret));
+                      OPT_ARG(PGPSUBKEY), gnutls_strerror (ret));
                   exit (1);
                 }
             }
@@ -547,8 +547,14 @@ init_tls_session (const char *hostname)
 {
   const char *err;
   int ret;
-
+  const char * priorities;
   gnutls_session_t session;
+  
+  if (HAVE_OPT(PRIORITY)) {
+    priorities = OPT_ARG(PRIORITY);
+  } else {
+    priorities = "NORMAL";
+  }
 
   if (udp)
     {
@@ -559,8 +565,7 @@ init_tls_session (const char *hostname)
   else
     gnutls_init (&session, GNUTLS_CLIENT);
 
-
-  if ((ret = gnutls_priority_set_direct (session, info.priorities, &err)) < 0)
+  if ((ret = gnutls_priority_set_direct (session, priorities, &err)) < 0)
     {
       if (ret == GNUTLS_E_INVALID_REQUEST) fprintf (stderr, "Syntax error at: %s\n", err);
       else 
@@ -610,14 +615,14 @@ init_tls_session (const char *hostname)
     }
 
 #ifdef ENABLE_SESSION_TICKET
-  if (disable_extensions == 0 && !info.noticket)
+  if (disable_extensions == 0 && !ENABLED_OPT(NOTICKET)t)
     gnutls_session_ticket_enable_client (session);
 #endif
 
   return session;
 }
 
-static void gaa_parser (int argc, char **argv);
+static void cmd_parser (int argc, char **argv);
 
 /* Returns zero if the error code was successfully handled.
  */
@@ -748,10 +753,10 @@ main (int argc, char **argv)
   ssize_t bytes;
 
   set_program_name (argv[0]);
-  gaa_parser (argc, argv);
+  cmd_parser (argc, argv);
 
   gnutls_global_set_log_function (tls_log_func);
-  gnutls_global_set_log_level (info.debug);
+  gnutls_global_set_log_level (OPT_VALUE_DEBUG);
 
   if ((ret = gnutls_global_init ()) < 0)
     {
@@ -827,7 +832,7 @@ main (int argc, char **argv)
           gnutls_session_get_id (hd.session, session_id, &session_id_size);
 
           /* print some information */
-          print_info (hd.session, hostname, info.insecure);
+          print_info (hd.session, hostname, ENABLED_OPT(INSECURE));
 
           printf ("- Disconnecting\n");
           socket_bye (&hd);
@@ -1009,58 +1014,89 @@ after_handshake:
   return retval;
 }
 
-void
-gaa_parser (int argc, char **argv)
+static void
+cmd_parser (int argc, char **argv)
 {
-  if (gaa (argc, argv, &info) != -1)
+const char* rest = NULL;
+
+  int optct = optionProcess( &gnutls_cliOptions, argc, argv);
+  argc -= optct;
+  argv += optct;
+  
+  if (rest == NULL && argc > 0)
+    rest = argv[0];
+  
+  verbose = ENABLED_OPT( VERBOSE);
+  disable_extensions = ENABLED_OPT( DISABLE_EXTENSIONS);
+  print_cert = ENABLED_OPT( PRINT_CERT);
+  starttls = ENABLED_OPT(STARTTLS);
+  resume = ENABLED_OPT(RESUME);
+  rehandshake = ENABLED_OPT(REHANDSHAKE);
+  insecure = ENABLED_OPT(INSECURE);
+  udp = ENABLED_OPT(UDP);
+  mtu = OPT_VALUE_MTU;
+  
+  if (HAVE_OPT(PORT)) 
     {
-      fprintf (stderr,
-               "Error in the arguments. Use the --help or -h parameters to get more information.\n");
-      exit (1);
+      service = OPT_ARG(PORT);
+    }
+  else 
+    {
+      service = "443";
     }
 
-  verbose = info.verbose;
-  disable_extensions = info.disable_extensions;
-  print_cert = info.print_cert;
-  starttls = info.starttls;
-  resume = info.resume;
-  rehandshake = info.rehandshake;
-  insecure = info.insecure;
-  udp = info.udp;
-  mtu = info.mtu;
-  service = info.port;
-  record_max_size = info.record_size;
-  fingerprint = info.fingerprint;
-
-  if (info.fmtder == 0)
-    x509ctype = GNUTLS_X509_FMT_PEM;
-  else
+  record_max_size = OPT_VALUE_RECORDSIZE;
+  fingerprint = ENABLED_OPT(FINGERPRINT);
+
+  if (ENABLED_OPT(X509FMTDER))
     x509ctype = GNUTLS_X509_FMT_DER;
+  else
+    x509ctype = GNUTLS_X509_FMT_PEM;
+
+  if (HAVE_OPT(SRPUSERNAME))
+    srp_username = OPT_ARG(SRPUSERNAME);
+    
+  if (HAVE_OPT(SRPPASSWD))
+    srp_passwd = OPT_ARG(SRPPASSWD);
+  
+  if (HAVE_OPT(X509CAFILE))
+    x509_cafile = OPT_ARG(X509CAFILE);
+  
+  if (HAVE_OPT(X509CRLFILE))
+    x509_crlfile = OPT_ARG(X509CRLFILE);
+    
+  if (HAVE_OPT(X509KEYFILE))
+    x509_keyfile = OPT_ARG(X509KEYFILE);
+  
+  if (HAVE_OPT(X509CERTFILE))
+    x509_certfile = OPT_ARG(X509CERTFILE);
+  
+  if (HAVE_OPT(PGPKEYFILE))
+    pgp_keyfile = OPT_ARG(PGPKEYFILE);
+  
+  if (HAVE_OPT(PGPCERTFILE))
+    pgp_certfile = OPT_ARG(PGPCERTFILE);
 
-  srp_username = info.srp_username;
-  srp_passwd = info.srp_passwd;
-  x509_cafile = info.x509_cafile;
-  x509_crlfile = info.x509_crlfile;
-  x509_keyfile = info.x509_keyfile;
-  x509_certfile = info.x509_certfile;
-  pgp_keyfile = info.pgp_keyfile;
-  pgp_certfile = info.pgp_certfile;
-
-  psk_username = info.psk_username;
-  psk_key.data = (unsigned char *) info.psk_key;
-  if (info.psk_key != NULL)
-    psk_key.size = strlen (info.psk_key);
+  if (HAVE_OPT(PSKUSERNAME))
+    psk_username = OPT_ARG(PSKUSERNAME);
+
+  if (HAVE_OPT(PSKKEY))
+    {
+      psk_key.data = (unsigned char *) OPT_ARG(PSKKEY);
+      psk_key.size = strlen (OPT_ARG(PSKKEY));
+    }
   else
     psk_key.size = 0;
 
-  pgp_keyring = info.pgp_keyring;
+  if (HAVE_OPT(PGPKEYRING))
+    pgp_keyring = OPT_ARG(PGPKEYRING);
 
-  crlf = info.crlf;
+  crlf = ENABLED_OPT(CRLF);
 
-  if (info.rest_args == NULL)
+  if (rest == NULL)
     hostname = "localhost";
   else
-    hostname = info.rest_args;
+    hostname = rest;
 }
 
 void cli_version (void);
@@ -1125,7 +1161,7 @@ do_handshake (socket_st * socket)
   if (ret == 0)
     {
       /* print some information */
-      print_info (socket->session, socket->hostname, info.insecure);
+      print_info (socket->session, socket->hostname, ENABLED_OPT(INSECURE));
 
 
       socket->secure = 1;
@@ -1169,8 +1205,8 @@ psk_callback (gnutls_session_t session, char **username, gnutls_datum_t * key)
   else
     printf ("No PSK hint\n");
 
-  if (info.psk_username)
-    *username = gnutls_strdup (info.psk_username);
+  if (HAVE_OPT(PSKUSERNAME))
+    *username = gnutls_strdup (OPT_ARG(PSKUSERNAME));
   else
     {
       char *tmp = NULL;
@@ -1224,7 +1260,7 @@ psk_callback (gnutls_session_t session, char **username, gnutls_datum_t * key)
   key->data = (void*)rawkey;
   key->size = res_size;
 
-  if (info.debug)
+  if (HAVE_OPT(DEBUG))
     {
       char hexkey[41];
       res_size = sizeof (hexkey);
diff --git a/src/cli.gaa b/src/cli.gaa
deleted file mode 100644 (file)
index c29fbb8..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#{
-
-/* C declarations */
-
-#include <config.h>
-#include <common.h>
-#include <benchmark.h>
-
-void cli_version(void);
-
-#}
-
-helpnode "GnuTLS test client\nUsage:  gnutls-cli [options] hostname\n\n"
-
-#int debug;
-option (d, debug) INT "integer" { $debug = $1 } "Enable debugging" 
-
-#int resume;
-option (r, resume) { $resume = 1 } "Connect, establish a session. Connect again and resume this session."
-
-#int rehandshake;
-option (e, rehandshake) { $rehandshake = 1 } "Connect, establish a session and rehandshake immediately."
-
-#int noticket;
-option (noticket) { $noticket = 1 } "Doesn't accept session tickets."
-
-#int starttls;
-option (s, starttls) { $starttls = 1 } "Connect, establish a plain session and start TLS when EOF or a SIGALRM is received."
-
-#int udp;
-option (u, udp) { $udp = 1 } "Use DTLS (datagram TLS) over UDP."
-
-#int mtu;
-option (mtu) INT "integer" { $mtu = $1 } "Set MTU for datagram TLS."
-
-#int crlf;
-option (crlf) { $crlf = 1 } "Send CR LF instead of LF."
-
-#int fmtder;
-option (x509fmtder) { $fmtder = 1 } "Use DER format for certificates to read from."
-
-#int fingerprint;
-option (f, fingerprint) { $fingerprint = 1 } "Send the openpgp fingerprint, instead of the key."
-
-#int disable_extensions;
-option ( disable-extensions) { $disable_extensions = 1 } "Disable all the TLS extensions."
-
-#int print_cert;
-option (print-cert) { $print_cert = 1 } "Print the certificate in PEM format."
-
-#int record_size;
-option (recordsize) INT "integer" { $record_size = $1 } "The maximum record size to advertize."
-
-#int verbose;
-option (V, verbose) { $verbose = 1 } "More verbose output."
-
-#char *priorities;
-option (priority) STR "PRIORITY STRING" { $priorities = $1 } "Priorities string."
-
-#char *x509_cafile;
-option (x509cafile) STR "FILE" { $x509_cafile = $1 } "Certificate file or PKCS #11 URL to use."
-
-#char *x509_crlfile;
-option (x509crlfile) STR "FILE" { $x509_crlfile = $1 } "CRL file to use."
-
-#char *pgp_keyfile;
-option (pgpkeyfile) STR "FILE" { $pgp_keyfile = $1 } "PGP Key file to use."
-
-#char *pgp_keyring;
-option (pgpkeyring) STR "FILE" { $pgp_keyring = $1 } "PGP Key ring file to use."
-
-#char *pgp_certfile;
-option (pgpcertfile) STR "FILE" { $pgp_certfile = $1 } "PGP Public Key (certificate) file to use."
-
-#char *pgp_subkey;
-option (pgpsubkey) STR "HEX|auto" { $pgp_subkey = $1 } "PGP subkey to use."
-
-#char *x509_keyfile;
-option (x509keyfile) STR "FILE" { $x509_keyfile = $1 } "X.509 key file or PKCS #11 URL to use."
-
-#char *x509_certfile;
-option (x509certfile) STR "FILE" { $x509_certfile = $1 } "X.509 Certificate file or PKCS #11 URL to use."
-
-#char *srp_username;
-option (srpusername) STR "NAME" { $srp_username = $1 } "SRP username to use."
-
-#char *srp_passwd;
-option (srppasswd) STR "PASSWD" { $srp_passwd = $1 } "SRP password to use."
-
-#char *psk_username;
-option (pskusername) STR "NAME" { $psk_username = $1 } "PSK username to use."
-
-#char *psk_key;
-option (pskkey) STR "KEY" { $psk_key = $1 } "PSK key (in hex) to use."
-
-#char *port;
-option (p, port) STR "PORT" { $port = $1 } "The port to connect to."
-
-#int insecure;
-option (insecure) { $insecure = 1 } "Don't abort program if server certificate can't be validated."
-
-option ( benchmark-ciphers) { benchmark_cipher(1, $debug); exit(0) } "Benchmark individual ciphers."
-option ( benchmark-soft-ciphers) { benchmark_cipher(0, $debug); exit(0) } "Benchmark individual software ciphers."
-option ( benchmark-tls) { benchmark_tls($debug); exit(0) } "Benchmark ciphers and key exchange methods in TLS."
-
-option (l, list) { print_list($priorities, $verbose); exit(0); } "Print a list of the supported algorithms and modes. If a priority string is given then only the ciphersuites enabled by the priority are shown."
-option (h, help) { gaa_help(); exit(0); } "prints this help"
-
-option (v, version) { cli_version(); exit(0); } "prints the program's version number"
-
-#char *rest_args;
-rest STR "hostname" { $rest_args = $1; }
-
-init { $resume=0; $noticket=0; $port="443"; $rest_args=NULL; 
-       $record_size=0; 
-       $fingerprint=0; $pgp_keyring=NULL; $x509_crlfile = NULL;
-       $x509_cafile = NULL; $pgp_keyfile=NULL; $pgp_certfile=NULL; $disable_extensions = 0;
-       $x509_keyfile=NULL; $x509_certfile=NULL; $crlf = 0; 
-       $srp_username=NULL; $srp_passwd=NULL; $fmtder = 0; $starttls =0; 
-       $debug = 0; $print_cert = 0; $verbose = 0; $psk_key = NULL; 
-       $psk_username = NULL; $priorities = NULL; $mtu = 1300;
-       $pgp_subkey = NULL; $rehandshake = 0; $udp = 0; }
index 8658846bae4f08bf96dddea3282b100b9fa4b595..4e61d8e4de6e3318d3c3bf2471a40dd944cb6466 100644 (file)
@@ -1,4 +1,3 @@
-#define PORT 5556
 #define SERVER "127.0.0.1"
 
 #include <config.h>
diff --git a/src/srptool-args.c b/src/srptool-args.c
new file mode 100644 (file)
index 0000000..02e6e3e
--- /dev/null
@@ -0,0 +1,597 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (srptool-args.c)
+ *  
+ *  It has been AutoGen-ed  January 19, 2012 at 09:24:17 PM by AutoGen 5.12
+ *  From the definitions    srptool-args.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 35:0:10 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This source file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the srptool author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * This source file is copyrighted and licensed under the following terms:
+ *
+ *  Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *  
+PFX>srptool is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  srptool is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#define OPTION_CODE_COMPILE 1
+#include "srptool-args.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+extern FILE * option_usage_fp;
+
+/* TRANSLATORS: choose the translation for option names wisely because you
+                cannot ever change your mind. */
+static char const zCopyright[275] =
+"srptool 3.0.11\n\
+Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.\n\
+This is free software. It is licensed for use, modification and\n\
+redistribution under the terms of the\n\
+GNU General Public License, version 3 or later\n\
+    <http://gnu.org/licenses/gpl.html>\n";
+static char const zLicenseDescrip[603] =
+"srptool is free software: you can redistribute it and/or modify it under\n\
+the terms of the GNU General Public License as published by the Free\n\
+Software Foundation, either version 3 of the License, or (at your option)\n\
+any later version.\n\n\
+srptool is distributed in the hope that it will be useful, but WITHOUT\n\
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n\
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n\
+for more details.\n\n\
+You should have received a copy of the GNU General Public License along\n\
+with this program.  If not, see <http://www.gnu.org/licenses/>.\n";
+
+extern tUsageProc optionUsage;
+
+#ifndef NULL
+#  define NULL 0
+#endif
+
+/*
+ *  Debug option description:
+ */
+static char const zDebugText[] =
+        "Enable debugging.";
+static char const zDebug_NAME[]              = "DEBUG";
+static char const zDebug_Name[]              = "debug";
+#define DEBUG_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+
+/*
+ *  Index option description:
+ */
+static char const zIndexText[] =
+        "specify the index of the group parameters in tpasswd.conf to use.";
+static char const zIndex_NAME[]              = "INDEX";
+static char const zIndex_Name[]              = "index";
+#define INDEX_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Username option description:
+ */
+static char const zUsernameText[] =
+        "specify a username";
+static char const zUsername_NAME[]           = "USERNAME";
+static char const zUsername_Name[]           = "username";
+#define USERNAME_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Passwd option description:
+ */
+static char const zPasswdText[] =
+        "specify a password file.";
+static char const zPasswd_NAME[]             = "PASSWD";
+static char const zPasswd_Name[]             = "passwd";
+#define PASSWD_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING))
+
+/*
+ *  Salt option description:
+ */
+static char const zSaltText[] =
+        "specify salt size for crypt algorithm.";
+static char const zSalt_NAME[]               = "SALT";
+static char const zSalt_Name[]               = "salt";
+#define SALT_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC))
+
+/*
+ *  Verify option description:
+ */
+static char const zVerifyText[] =
+        "just verify the password.";
+static char const zVerify_NAME[]             = "VERIFY";
+static char const zVerify_Name[]             = "verify";
+#define VERIFY_FLAGS       (OPTST_DISABLED)
+
+/*
+ *  Passwd_Conf option description:
+ */
+static char const zPasswd_ConfText[] =
+        "specify a password conf file.";
+static char const zPasswd_Conf_NAME[]        = "PASSWD_CONF";
+static char const zPasswd_Conf_Name[]        = "passwd-conf";
+#define PASSWD_CONF_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Create_Conf option description:
+ */
+static char const zCreate_ConfText[] =
+        "Generate a password configuration file.";
+static char const zCreate_Conf_NAME[]        = "CREATE_CONF";
+static char const zCreate_Conf_Name[]        = "create-conf";
+#define CREATE_CONF_FLAGS       (OPTST_DISABLED \
+        | OPTST_SET_ARGTYPE(OPARG_TYPE_FILE))
+
+/*
+ *  Help/More_Help/Version option descriptions:
+ */
+static char const zHelpText[]          = "Display extended usage information and exit";
+static char const zHelp_Name[]         = "help";
+#ifdef HAVE_WORKING_FORK
+#define OPTST_MORE_HELP_FLAGS   (OPTST_IMM | OPTST_NO_INIT)
+static char const zMore_Help_Name[]    = "more-help";
+static char const zMore_HelpText[]     = "Extended usage information passed thru pager";
+#else
+#define OPTST_MORE_HELP_FLAGS   (OPTST_OMITTED | OPTST_NO_INIT)
+#define zMore_Help_Name   NULL
+#define zMore_HelpText    NULL
+#endif
+#ifdef NO_OPTIONAL_OPT_ARGS
+#  define OPTST_VERSION_FLAGS   OPTST_IMM | OPTST_NO_INIT
+#else
+#  define OPTST_VERSION_FLAGS   OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \
+                                OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT
+#endif
+
+static char const zVersionText[]       = "Output version information and exit";
+static char const zVersion_Name[]      = "version";
+/*
+ *  Declare option callback procedures
+ */
+extern tOptProc
+    optionBooleanVal,    optionNestedVal,     optionNumericVal,
+    optionPagedUsage,    optionPrintVersion,  optionResetOpt,
+    optionStackArg,      optionTimeDate,      optionTimeVal,
+    optionUnstackArg,    optionVersionStderr;
+static tOptProc
+    doOptCreate_Conf, doOptDebug, doOptPasswd_Conf, doUsageOpt;
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Srptool Option Descriptions.
+ */
+static tOptDesc optDesc[OPTION_CT] = {
+  {  /* entry idx, value */ 0, VALUE_OPT_DEBUG,
+     /* equiv idx, value */ 0, VALUE_OPT_DEBUG,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ DEBUG_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptDebug,
+     /* desc, NAME, name */ zDebugText, zDebug_NAME, zDebug_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 1, VALUE_OPT_INDEX,
+     /* equiv idx, value */ 1, VALUE_OPT_INDEX,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ INDEX_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zIndexText, zIndex_NAME, zIndex_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 2, VALUE_OPT_USERNAME,
+     /* equiv idx, value */ 2, VALUE_OPT_USERNAME,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ USERNAME_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zUsernameText, zUsername_NAME, zUsername_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 3, VALUE_OPT_PASSWD,
+     /* equiv idx, value */ 3, VALUE_OPT_PASSWD,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PASSWD_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zPasswdText, zPasswd_NAME, zPasswd_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 4, VALUE_OPT_SALT,
+     /* equiv idx, value */ 4, VALUE_OPT_SALT,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ SALT_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ optionNumericVal,
+     /* desc, NAME, name */ zSaltText, zSalt_NAME, zSalt_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 5, VALUE_OPT_VERIFY,
+     /* equiv idx, value */ 5, VALUE_OPT_VERIFY,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ VERIFY_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ NULL,
+     /* desc, NAME, name */ zVerifyText, zVerify_NAME, zVerify_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 6, VALUE_OPT_PASSWD_CONF,
+     /* equiv idx, value */ 6, VALUE_OPT_PASSWD_CONF,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ PASSWD_CONF_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptPasswd_Conf,
+     /* desc, NAME, name */ zPasswd_ConfText, zPasswd_Conf_NAME, zPasswd_Conf_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ 7, VALUE_OPT_CREATE_CONF,
+     /* equiv idx, value */ 7, VALUE_OPT_CREATE_CONF,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ CREATE_CONF_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doOptCreate_Conf,
+     /* desc, NAME, name */ zCreate_ConfText, zCreate_Conf_NAME, zCreate_Conf_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ INDEX_OPT_VERSION, VALUE_OPT_VERSION,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_VERSION_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ optionPrintVersion,
+     /* desc, NAME, name */ zVersionText, NULL, zVersion_Name,
+     /* disablement strs */ NULL, NULL },
+
+
+
+  {  /* entry idx, value */ INDEX_OPT_HELP, VALUE_OPT_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_IMM | OPTST_NO_INIT, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL, NULL,
+     /* option proc      */ doUsageOpt,
+     /* desc, NAME, name */ zHelpText, NULL, zHelp_Name,
+     /* disablement strs */ NULL, NULL },
+
+  {  /* entry idx, value */ INDEX_OPT_MORE_HELP, VALUE_OPT_MORE_HELP,
+     /* equiv idx value  */ NO_EQUIVALENT, 0,
+     /* equivalenced to  */ NO_EQUIVALENT,
+     /* min, max, act ct */ 0, 1, 0,
+     /* opt state flags  */ OPTST_MORE_HELP_FLAGS, 0,
+     /* last opt argumnt */ { NULL },
+     /* arg list/cookie  */ NULL,
+     /* must/cannot opts */ NULL,  NULL,
+     /* option proc      */ optionPagedUsage,
+     /* desc, NAME, name */ zMore_HelpText, NULL, zMore_Help_Name,
+     /* disablement strs */ NULL, NULL }
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Define the Srptool Option Environment
+ */
+static char const zPROGNAME[8] = "SRPTOOL";
+static char const zUsageTitle[99] =
+"srptool - GnuTLS SRP tool - Ver. 3.0.11\n\
+USAGE:  %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \n";
+#define zRcName     NULL
+#define apzHomeList NULL
+
+static char const zBugsAddr[19]    = "bug-gnutls@gnu.org";
+#define zExplain NULL
+static char const zDetail[473] = "\n\
+Simple program that emulates the programs in the Stanford SRP (Secure\n\
+Remote Password) libraries using GnuTLS.  It is intended for use in\n\
+places where you don't expect SRP authentication to be the used for\n\
+system users.\n\n\
+In  brief,  to use SRP you need to create two files. These are the\n\
+password file that holds the users and the verifiers associated with\n\
+them  and  the configuration file to hold the group parameters (called\n\
+tpasswd.conf).\n";
+static char const zFullVersion[] = SRPTOOL_FULL_VERSION;
+/* extracted from optcode.tlib near line 515 */
+
+#if defined(ENABLE_NLS)
+# define OPTPROC_BASE OPTPROC_TRANSLATE
+  static tOptionXlateProc translate_option_strings;
+#else
+# define OPTPROC_BASE OPTPROC_NONE
+# define translate_option_strings NULL
+#endif /* ENABLE_NLS */
+
+
+#define srptool_full_usage NULL
+static char const srptool_short_usage[] =
+       "srptool [options]\n\
+srptool --help for usage instructions.\n";
+
+#ifndef  PKGDATADIR
+# define PKGDATADIR ""
+#endif
+
+#ifndef  WITH_PACKAGER
+# define srptool_packager_info NULL
+#else
+static char const srptool_packager_info[] =
+    "Packaged by " WITH_PACKAGER
+
+# ifdef WITH_PACKAGER_VERSION
+        " ("WITH_PACKAGER_VERSION")"
+# endif
+
+# ifdef WITH_PACKAGER_BUG_REPORTS
+    "\nReport srptool bugs to " WITH_PACKAGER_BUG_REPORTS
+# endif
+    "\n";
+#endif
+
+tOptions srptoolOptions = {
+    OPTIONS_STRUCT_VERSION,
+    0, NULL,                    /* original argc + argv    */
+    ( OPTPROC_BASE
+    + OPTPROC_ERRSTOP
+    + OPTPROC_SHORTOPT
+    + OPTPROC_LONGOPT
+    + OPTPROC_NO_REQ_OPT
+    + OPTPROC_ARGS_REQ
+    + OPTPROC_REORDER
+    + OPTPROC_GNUUSAGE
+    + OPTPROC_MISUSE ),
+    0, NULL,                    /* current option index, current option */
+    NULL,         NULL,         zPROGNAME,
+    zRcName,      zCopyright,   zLicenseDescrip,
+    zFullVersion, apzHomeList,  zUsageTitle,
+    zExplain,     zDetail,      optDesc,
+    zBugsAddr,                  /* address to send bugs to */
+    NULL, NULL,                 /* extensions/saved state  */
+    optionUsage, /* usage procedure */
+    translate_option_strings,   /* translation procedure */
+    /*
+     *  Indexes to special options
+     */
+    { INDEX_OPT_MORE_HELP, /* more-help option index */
+      NO_EQUIVALENT, /* save option index */
+      NO_EQUIVALENT, /* '-#' option index */
+      NO_EQUIVALENT /* index of default opt */
+    },
+    11 /* full option count */, 8 /* user option count */,
+    srptool_full_usage, srptool_short_usage,
+    NULL, NULL,
+    PKGDATADIR, srptool_packager_info
+};
+
+/*
+ *  Create the static procedure(s) declared above.
+ */
+static void
+doUsageOpt(tOptions * pOptions, tOptDesc * pOptDesc)
+{
+    (void)pOptions;
+    USAGE(SRPTOOL_EXIT_SUCCESS);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the debug option.
+ */
+static void
+doOptDebug(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static const struct {long const rmin, rmax;} rng[1] = {
+        { 0 ,  9999 } };
+    int  ix;
+
+    if (pOptions <= OPTPROC_EMIT_LIMIT)
+        goto emit_ranges;
+    optionNumericVal(pOptions, pOptDesc);
+
+    for (ix = 0; ix < 1; ix++) {
+        if (pOptDesc->optArg.argInt < rng[ix].rmin)
+            continue;  /* ranges need not be ordered. */
+        if (pOptDesc->optArg.argInt == rng[ix].rmin)
+            return;
+        if (rng[ix].rmax == LONG_MIN)
+            continue;
+        if (pOptDesc->optArg.argInt <= rng[ix].rmax)
+            return;
+    }
+
+    option_usage_fp = stderr;
+
+emit_ranges:
+
+    optionShowRange(pOptions, pOptDesc, (void *)rng, 1);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the passwd-conf option.
+ */
+static void
+doOptPasswd_Conf(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *   For the create-conf option.
+ */
+static void
+doOptCreate_Conf(tOptions* pOptions, tOptDesc* pOptDesc)
+{
+    static teOptFileType const  type =
+        FTYPE_MODE_MAY_EXIST + FTYPE_MODE_NO_OPEN;
+    static tuFileMode           mode;
+#ifndef O_CLOEXEC
+#  define O_CLOEXEC 0
+#endif
+    mode.file_flags = O_CLOEXEC;
+
+    optionFileCheck(pOptions, pOptDesc, type, mode);
+}
+/* extracted from optcode.tlib near line 666 */
+
+#if ENABLE_NLS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <autoopts/usage-txt.h>
+
+static char* AO_gettext(char const* pz);
+static void  coerce_it(void** s);
+
+static char*
+AO_gettext(char const* pz)
+{
+    char* pzRes;
+    if (pz == NULL)
+        return NULL;
+    pzRes = _(pz);
+    if (pzRes == pz)
+        return pzRes;
+    pzRes = strdup(pzRes);
+    if (pzRes == NULL) {
+        fputs(_("No memory for duping translated strings\n"), stderr);
+        exit(SRPTOOL_EXIT_FAILURE);
+    }
+    return pzRes;
+}
+
+static void coerce_it(void** s) { *s = AO_gettext(*s);
+}
+
+/*
+ *  This invokes the translation code (e.g. gettext(3)).
+ */
+static void
+translate_option_strings(void)
+{
+    tOptions * const pOpt = &srptoolOptions;
+
+    /*
+     *  Guard against re-translation.  It won't work.  The strings will have
+     *  been changed by the first pass through this code.  One shot only.
+     */
+    if (option_usage_text.field_ct != 0) {
+        /*
+         *  Do the translations.  The first pointer follows the field count
+         *  field.  The field count field is the size of a pointer.
+         */
+        tOptDesc * pOD = pOpt->pOptDesc;
+        char **    ppz = (char**)(void*)&(option_usage_text);
+        int        ix  = option_usage_text.field_ct;
+
+        do {
+            ppz++;
+            *ppz = AO_gettext(*ppz);
+        } while (--ix > 0);
+
+        coerce_it((void*)&(pOpt->pzCopyright));
+        coerce_it((void*)&(pOpt->pzCopyNotice));
+        coerce_it((void*)&(pOpt->pzFullVersion));
+        coerce_it((void*)&(pOpt->pzUsageTitle));
+        coerce_it((void*)&(pOpt->pzExplain));
+        coerce_it((void*)&(pOpt->pzDetail));
+        coerce_it((void*)&(pOpt->pzPackager));
+        coerce_it((void*)&(pOpt->pzShortUsage));
+        option_usage_text.field_ct = 0;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++)
+            coerce_it((void*)&(pOD->pzText));
+    }
+
+    if ((pOpt->fOptSet & OPTPROC_NXLAT_OPT_CFG) == 0) {
+        tOptDesc * pOD = pOpt->pOptDesc;
+        int        ix;
+
+        for (ix = pOpt->optCt; ix > 0; ix--, pOD++) {
+            coerce_it((void*)&(pOD->pz_Name));
+            coerce_it((void*)&(pOD->pz_DisableName));
+            coerce_it((void*)&(pOD->pz_DisablePfx));
+        }
+        /* prevent re-translation */
+        srptoolOptions.fOptSet |= OPTPROC_NXLAT_OPT_CFG | OPTPROC_NXLAT_OPT;
+    }
+}
+
+#endif /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+/* srptool-args.c ends here */
diff --git a/src/srptool-args.def.in b/src/srptool-args.def.in
new file mode 100644 (file)
index 0000000..e3375bb
--- /dev/null
@@ -0,0 +1,129 @@
+AutoGen Definitions options;
+prog-name     = srptool;
+prog-title    = "GnuTLS SRP tool";
+prog-desc     = "Simple program to create SRP parameters.\n";
+detail    = "Simple program that emulates the programs in the Stanford SRP (Secure
+Remote Password) libraries using GnuTLS.  It is intended for use in  places
+where you don't expect SRP authentication to be the used for system users.
+
+In  brief,  to use SRP you need to create two files. These are the password
+file that holds the users and the verifiers associated with  them  and  the
+configuration file to hold the group parameters (called tpasswd.conf).";
+
+short-usage   = "srptool [options]\nsrptool --help for usage instructions.\n";
+prog-group    = "GnuTLS";
+gnu-usage;
+no-misuse-usage;
+reorder-args;
+disable-save;
+argument;
+long-opts;
+config-header = 'config.h';
+export = '#include <gettext.h>';
+
+copyright = {
+    date  = "2000-2012";
+    owner = "Free Software Foundation";
+    author = "Nikos Mavrogiannopoulos and Simon Josefsson";
+    eaddr  = "bug-gnutls@gnu.org";
+    type  = gpl;
+};
+version = "@VERSION@";
+
+flag = {
+    name      = debug;
+    value     = d;
+    arg-type  = number;
+    arg-range = "0 -> 9999";
+    descrip   = "Enable debugging.";
+    doc       = "Specifies the debug level.";
+};
+
+flag = {
+    name      = index;
+    value     = i;
+    descrip   = "specify the index of the group parameters in tpasswd.conf to use.";
+    doc = "";
+};
+
+flag = {
+    name      = username;
+    value     = u;
+    arg-type  = string;
+    descrip   = "specify a username";
+    doc = "";
+};
+
+flag = {
+    name      = passwd;
+    value     = p;
+    arg-type  = string;
+    descrip   = "specify a password file.";
+    doc       = "";
+};
+
+flag = {
+    name      = salt;
+    value     = s;
+    arg-type  = number;
+    descrip   = "specify salt size for crypt algorithm.";
+    doc = "";
+};
+
+flag = {
+    name      = verify;
+    descrip   = "just verify the password.";
+    doc       = "Verifies the password provided against the password file.";
+};
+
+flag = {
+    name      = passwd-conf;
+    value     = v;
+    arg-type  = file;
+    file-exists;
+    descrip   = "specify a password conf file.";
+    doc   = "Specify a filename or a PKCS #11 URL to read the CAs from.";
+};
+
+flag = {
+    name      = create-conf;
+    arg-type  = file;
+    descrip   = "Generate a password configuration file.";
+    doc   = "This generates a password configuration file (tpasswd.conf)
+containing the required for TLS parameters.";
+};
+
+doc-section = {
+  ds-type = 'SEE ALSO';
+  ds-format = 'man';
+  ds-text   = <<-_EOT_
+    gnutls-cli-debug (1), gnutls-serv (1), srptool (1), psktool (1), certtool (1)
+_EOT_;
+};
+
+doc-section = {
+  ds-type = 'EXAMPLES';
+  ds-format = 'texi';
+  ds-text   = <<-_EOT_
+To create @file{tpasswd.conf} which holds the g and n values for SRP protocol
+(generator and a large prime), run:
+@example
+$ srptool --create-conf /etc/tpasswd.conf
+@end example
+
+This command will create @file{/etc/tpasswd} and will add user 'test' (you
+will also be prompted for a password). Verifiers are stored by default
+in the way libsrp expects.
+@example
+srptool --passwd /etc/tpasswd --passwd-conf /etc/tpasswd.conf -u test
+@end example
+
+
+This command will check against a password. If the password matches
+the one in @file{/etc/tpasswd} you will get an ok.
+@example
+$ srptool --passwd /etc/tpasswd --passwd\-conf /etc/tpasswd.conf --verify -u test
+@end example
+_EOT_;
+};
+
diff --git a/src/srptool-args.h b/src/srptool-args.h
new file mode 100644 (file)
index 0000000..18be37d
--- /dev/null
@@ -0,0 +1,198 @@
+/*   -*- buffer-read-only: t -*- vi: set ro:
+ *  
+ *  DO NOT EDIT THIS FILE   (srptool-args.h)
+ *  
+ *  It has been AutoGen-ed  January 19, 2012 at 09:24:17 PM by AutoGen 5.12
+ *  From the definitions    srptool-args.def
+ *  and the template file   options
+ *
+ * Generated from AutoOpts 35:0:10 templates.
+ *
+ *  AutoOpts is a copyrighted work.  This header file is not encumbered
+ *  by AutoOpts licensing, but is provided under the licensing terms chosen
+ *  by the srptool author or copyright holder.  AutoOpts is
+ *  licensed under the terms of the LGPL.  The redistributable library
+ *  (``libopts'') is licensed under the terms of either the LGPL or, at the
+ *  users discretion, the BSD license.  See the AutoOpts and/or libopts sources
+ *  for details.
+ *
+ * This source file is copyrighted and licensed under the following terms:
+ *
+ *  Copyright (C) 2000-2012 Free Software Foundation, all rights reserved.
+ *  This is free software. It is licensed for use, modification and
+ *  redistribution under the terms of the
+ *  GNU General Public License, version 3 or later
+ *      <http://gnu.org/licenses/gpl.html>
+ *  
+PFX>srptool is free software: you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  srptool is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *  See the GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ *  This file contains the programmatic interface to the Automated
+ *  Options generated for the srptool program.
+ *  These macros are documented in the AutoGen info file in the
+ *  "AutoOpts" chapter.  Please refer to that doc for usage help.
+ */
+#ifndef AUTOOPTS_SRPTOOL_ARGS_H_GUARD
+#define AUTOOPTS_SRPTOOL_ARGS_H_GUARD 1
+#include "config.h"
+#include <autoopts/options.h>
+
+/*
+ *  Ensure that the library used for compiling this generated header is at
+ *  least as new as the version current when the header template was released
+ *  (not counting patch version increments).  Also ensure that the oldest
+ *  tolerable version is at least as old as what was current when the header
+ *  template was released.
+ */
+#define AO_TEMPLATE_VERSION 143360
+#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
+ || (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
+# error option template version mismatches autoopts/options.h header
+  Choke Me.
+#endif
+
+/*
+ *  Enumeration of each option:
+ */
+typedef enum {
+    INDEX_OPT_DEBUG        =  0,
+    INDEX_OPT_INDEX        =  1,
+    INDEX_OPT_USERNAME     =  2,
+    INDEX_OPT_PASSWD       =  3,
+    INDEX_OPT_SALT         =  4,
+    INDEX_OPT_VERIFY       =  5,
+    INDEX_OPT_PASSWD_CONF  =  6,
+    INDEX_OPT_CREATE_CONF  =  7,
+    INDEX_OPT_VERSION      =  8,
+    INDEX_OPT_HELP         =  9,
+    INDEX_OPT_MORE_HELP    = 10
+} teOptIndex;
+
+#define OPTION_CT    11
+#define SRPTOOL_VERSION       "3.0.11"
+#define SRPTOOL_FULL_VERSION  "srptool 3.0.11"
+
+/*
+ *  Interface defines for all options.  Replace "n" with the UPPER_CASED
+ *  option name (as in the teOptIndex enumeration above).
+ *  e.g. HAVE_OPT(DEBUG)
+ */
+#define         DESC(n) (srptoolOptions.pOptDesc[INDEX_OPT_## n])
+#define     HAVE_OPT(n) (! UNUSED_OPT(& DESC(n)))
+#define      OPT_ARG(n) (DESC(n).optArg.argString)
+#define    STATE_OPT(n) (DESC(n).fOptState & OPTST_SET_MASK)
+#define    COUNT_OPT(n) (DESC(n).optOccCt)
+#define    ISSEL_OPT(n) (SELECTED_OPT(&DESC(n)))
+#define ISUNUSED_OPT(n) (UNUSED_OPT(& DESC(n)))
+#define  ENABLED_OPT(n) (! DISABLED_OPT(& DESC(n)))
+#define  STACKCT_OPT(n) (((tArgList*)(DESC(n).optCookie))->useCt)
+#define STACKLST_OPT(n) (((tArgList*)(DESC(n).optCookie))->apzArgs)
+#define    CLEAR_OPT(n) STMTS( \
+                DESC(n).fOptState &= OPTST_PERSISTENT_MASK;   \
+                if ((DESC(n).fOptState & OPTST_INITENABLED) == 0) \
+                    DESC(n).fOptState |= OPTST_DISABLED; \
+                DESC(n).optCookie = NULL )
+
+/* * * * * *
+ *
+ *  Enumeration of srptool exit codes
+ */
+typedef enum {
+    SRPTOOL_EXIT_SUCCESS = 0,
+    SRPTOOL_EXIT_FAILURE = 1
+} srptool_exit_code_t;
+/* * * * * *
+ *
+ *  Interface defines for specific options.
+ */
+#define VALUE_OPT_DEBUG          'd'
+
+#define OPT_VALUE_DEBUG          (DESC(DEBUG).optArg.argInt)
+#define VALUE_OPT_INDEX          'i'
+#define VALUE_OPT_USERNAME       'u'
+#define VALUE_OPT_PASSWD         'p'
+#define VALUE_OPT_SALT           's'
+
+#define OPT_VALUE_SALT           (DESC(SALT).optArg.argInt)
+#define VALUE_OPT_VERIFY         5
+#define VALUE_OPT_PASSWD_CONF    'v'
+#define VALUE_OPT_CREATE_CONF    7
+#define VALUE_OPT_HELP          '?'
+#define VALUE_OPT_MORE_HELP     '!'
+#define VALUE_OPT_VERSION       'v'
+/*
+ *  Interface defines not associated with particular options
+ */
+#define ERRSKIP_OPTERR  STMTS(srptoolOptions.fOptSet &= ~OPTPROC_ERRSTOP)
+#define ERRSTOP_OPTERR  STMTS(srptoolOptions.fOptSet |= OPTPROC_ERRSTOP)
+#define RESTART_OPT(n)  STMTS( \
+                srptoolOptions.curOptIdx = (n); \
+                srptoolOptions.pzCurOpt  = NULL)
+#define START_OPT       RESTART_OPT(1)
+#define USAGE(c)        (*srptoolOptions.pUsageProc)(&srptoolOptions, c)
+/* extracted from opthead.tlib near line 451 */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* * * * * *
+ *
+ *  Globals exported from the GnuTLS SRP tool option definitions
+ */
+#include <gettext.h>
+
+/* * * * * *
+ *
+ *  Declare the srptool option descriptor.
+ */
+extern tOptions srptoolOptions;
+
+#if defined(ENABLE_NLS)
+# ifndef _
+#   include <stdio.h>
+static inline char* aoGetsText(char const* pz) {
+    if (pz == NULL) return NULL;
+    return (char*)gettext(pz);
+}
+#   define _(s)  aoGetsText(s)
+# endif /* _() */
+
+# define OPT_NO_XLAT_CFG_NAMES  STMTS(srptoolOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT_CFG;)
+# define OPT_NO_XLAT_OPT_NAMES  STMTS(srptoolOptions.fOptSet |= \
+                                    OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG;)
+
+# define OPT_XLAT_CFG_NAMES     STMTS(srptoolOptions.fOptSet &= \
+                                  ~(OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG);)
+# define OPT_XLAT_OPT_NAMES     STMTS(srptoolOptions.fOptSet &= \
+                                  ~OPTPROC_NXLAT_OPT;)
+
+#else   /* ENABLE_NLS */
+# define OPT_NO_XLAT_CFG_NAMES
+# define OPT_NO_XLAT_OPT_NAMES
+
+# define OPT_XLAT_CFG_NAMES
+# define OPT_XLAT_OPT_NAMES
+
+# ifndef _
+#   define _(_s)  _s
+# endif
+#endif  /* ENABLE_NLS */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif /* AUTOOPTS_SRPTOOL_ARGS_H_GUARD */
+/* srptool-args.h ends here */
index 1d4db32fe81ce42c999c0b099f40a3484da55cc1..8c092940195e849a5f1822e825cd7e1b537bb705 100644 (file)
@@ -24,7 +24,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include <gnutls/gnutls.h>
-#include <srptool-gaa.h>
 #include <gnutls/crypto.h>      /* for random */
 
 #include <sys/types.h>
 #include <progname.h>
 #include <version-etc.h>
 
+#include <gettext.h>
+#include <srptool-args.h>
+
 /* This may need some rewrite. A lot of stuff which should be here
  * are in the library, which is not good.
  */
 
 int crypt_int (const char *username, const char *passwd, int salt,
-               char *tpasswd_conf, char *tpasswd, int uindex);
+               const char *tpasswd_conf, const char *tpasswd, int uindex);
 static int read_conf_values (gnutls_datum_t * g, gnutls_datum_t * n,
                              char *str);
 static int _verify_passwd_int (const char *username, const char *passwd,
-                               char *verifier, char *salt,
+                               char *verifier, const char *salt,
                                const gnutls_datum_t * g,
                                const gnutls_datum_t * n);
 
@@ -76,7 +78,7 @@ print_num (const char *msg, const gnutls_datum_t * num)
 }
 
 static int
-generate_create_conf (char *tpasswd_conf)
+generate_create_conf (const char *tpasswd_conf)
 {
   FILE *fd;
   char line[5 * 1024];
@@ -163,7 +165,7 @@ generate_create_conf (char *tpasswd_conf)
  */
 static int
 _verify_passwd_int (const char *username, const char *passwd,
-                    char *verifier, char *salt,
+                    char *verifier, const char *salt,
                     const gnutls_datum_t * g, const gnutls_datum_t * n)
 {
   char _salt[1024];
@@ -229,7 +231,7 @@ _verify_passwd_int (const char *username, const char *passwd,
 }
 
 static int
-filecopy (char *src, char *dst)
+filecopy (const char *src, const char *dst)
 {
   FILE *fd, *fd2;
   char line[5 * 1024];
@@ -269,7 +271,7 @@ filecopy (char *src, char *dst)
 
 /* accepts password file */
 static int
-find_strchr (char *username, char *file)
+find_strchr (const char *username, const char *file)
 {
   FILE *fd;
   char *pos;
@@ -309,8 +311,8 @@ find_strchr (char *username, char *file)
  * username/password pair.
  */
 static int
-verify_passwd (char *conffile, char *tpasswd, char *username,
-               const char *passwd)
+verify_passwd (const char *conffile, const char *tpasswd, 
+               const char *username, const char *passwd)
 {
   FILE *fd;
   char line[5 * 1024];
@@ -416,9 +418,11 @@ tls_log_func (int level, const char *str)
 
 int main (int argc, char **argv)
 {
-  gaainfo info;
   const char *passwd;
   int salt_size, ret;
+  int optct;
+  const char* fpasswd, *fpasswd_conf;
+  const char* username;
 #ifndef _WIN32
    struct passwd *pwd;
 #endif
@@ -433,26 +437,31 @@ int main (int argc, char **argv)
 
   umask (066);
 
-  if (gaa (argc, argv, &info) != -1)
-    {
-      fprintf (stderr, "Error in the arguments.\n");
-      return -1;
-    }
+  optct = optionProcess( &srptoolOptions, argc, argv);
+  argc -= optct;
+  argv += optct;
 
   gnutls_global_set_log_function (tls_log_func);
-  gnutls_global_set_log_level (info.debug);
+  gnutls_global_set_log_level (OPT_VALUE_DEBUG);
 
-  if (info.create_conf != NULL)
+  if (HAVE_OPT(CREATE_CONF))
     {
-      return generate_create_conf (info.create_conf);
+      return generate_create_conf (OPT_ARG(CREATE_CONF));
     }
 
-  if (info.passwd == NULL)
-    info.passwd = (char *) KPASSWD;
-  if (info.passwd_conf == NULL)
-    info.passwd_conf = (char *) KPASSWD_CONF;
+  if (HAVE_OPT(PASSWD))
+    fpasswd = OPT_ARG(PASSWD);
+  else
+    fpasswd = (char *) KPASSWD;
+
+  if (HAVE_OPT(PASSWD_CONF))
+    fpasswd_conf = OPT_ARG(PASSWD_CONF);
+  else
+    fpasswd_conf = (char *) KPASSWD_CONF;
 
-  if (info.username == NULL)
+  if (HAVE_OPT(USERNAME))
+    username = OPT_ARG(USERNAME);
+  else
     {
 #ifndef _WIN32
       pwd = getpwuid (getuid ());
@@ -463,7 +472,7 @@ int main (int argc, char **argv)
           return -1;
         }
 
-      info.username = pwd->pw_name;
+      username = pwd->pw_name;
 #else
       fprintf (stderr, "Please specify a user\n");
       return -1;
@@ -480,15 +489,15 @@ int main (int argc, char **argv)
     }
 
 /* not ready yet */
-  if (info.verify != 0)
+  if (HAVE_OPT(VERIFY))
     {
-      return verify_passwd (info.passwd_conf, info.passwd,
-                            info.username, passwd);
+      return verify_passwd (fpasswd_conf, fpasswd,
+                            username, passwd);
     }
 
 
-  return crypt_int (info.username, passwd, salt_size,
-                    info.passwd_conf, info.passwd, info.index);
+  return crypt_int (username, passwd, salt_size,
+                    fpasswd_conf, fpasswd, VALUE_OPT_INDEX);
 
 }
 
@@ -548,7 +557,7 @@ _srp_crypt (const char *username, const char *passwd, int salt_size,
 
 int
 crypt_int (const char *username, const char *passwd, int salt_size,
-           char *tpasswd_conf, char *tpasswd, int uindex)
+           const char *tpasswd_conf, const char *tpasswd, int uindex)
 {
   FILE *fd;
   char *cr;
diff --git a/src/srptool.gaa b/src/srptool.gaa
deleted file mode 100644 (file)
index 0026b0a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#{
-
-/* C declarations */
-
-#include <config.h>
-#ifdef _WIN32
-# include <io.h>
-#endif
-
-void srptool_version(void);
-
-#}
-
-helpnode "Srptool help\nUsage : srptool [options]"
-
-#int debug;
-option (d, debug) INT "integer" { $debug = $1 } "Enable debugging" 
-
-#char *username;
-option (u,username) STR "username" { $username = $1 } "specify username."
-
-#char *passwd;
-option (p, passwd) STR "FILE" { $passwd = $1 } "specify a password file."
-
-#int index;
-option (i, index) INT "INDEX" { $index = $1 } "specify the index of the group parameters in tpasswd.conf to use."
-
-#int salt;
-option (s, salt) INT "SALT" { $salt = $1 } "specify salt size for crypt algorithm."
-
-#int verify;
-option (verify) { $verify = 1 } "just verify password."
-
-#char *passwd_conf;
-option (c, passwd-conf) STR "FILE" { $passwd_conf = $1 } "specify a password conf file."
-
-#char *create_conf;
-option ( create-conf) STR "FILE" { $create_conf = $1 } "Generate a tpasswd.conf file."
-
-option (v, version) { srptool_version(); exit(0); } "prints the program's version number"
-option (h, help) { gaa_help(); exit(0); } "shows this help text"
-
-init { $username=NULL; $passwd=NULL; $salt=0;
-       $create_conf=NULL; $passwd_conf=NULL; $verify = 0; 
-       $index = 1; $debug = 0; }
diff --git a/src/tls_test-gaa.c b/src/tls_test-gaa.c
deleted file mode 100644 (file)
index d27ee1c..0000000
+++ /dev/null
@@ -1,795 +0,0 @@
-/* File generated by GAA 1.6.6
- */
-#define GAA_NO_WIN32
-#line 1 "tls_test.gaa"
-
-
-/* C declarations */
-
-#include <config.h>
-#ifdef _WIN32
-# include <io.h>
-#endif
-
-void tls_test_version(void);
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifndef GAA_NO_WIN32
-#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(WINDOWS)
-#define GAA_WIN32
-#endif
-#endif
-
-static void* gaa_malloc( size_t size) {
-void* ret;
-       ret = malloc(size);
-       if (ret==NULL) {
-               fprintf(stderr, "gaa: could not allocate memory");
-               exit(1);
-       }
-       return ret;
-}
-
-static void __gaa_helpsingle(char short_name, char *name, 
-       char *arg_desc, char *opt_help)
-{
-     int col1, col3, col4, tabsize = 3, curr;
-     int i;
-
-     col1 = 5; /* Default values */
-     col3 = 30;
-     col4 = 70;
-
-     curr = 0;
-     for(i = 0; i < col1; i++)
-        {
-        printf(" ");
-        curr++;
-        }
-     if(short_name)
-        {
-        if(name && *name)
-          {
-            printf("-%c, ", short_name);
-            curr += 4;
-          }
-        else
-          {
-            printf("-%c ", short_name);
-            curr += 3;
-          }
-        }
-     if(name && *name)
-        {
-          printf("--%s ", name);
-          curr += 3 + strlen(name);
-        }
-     if(arg_desc && *arg_desc)
-        {
-          printf("%s ", arg_desc);
-          curr += 1 + strlen(arg_desc);
-        }
-     if(curr >= col3)
-        {
-          printf("\n");
-          curr = 0;
-        }
-     if(opt_help) /* let's print the option's help body */
-        {
-        const char *str = opt_help;
-        while(*str)
-          {
-             while(curr < col3)
-               {
-                 printf(" ");
-                 curr++;
-               }
-             switch(*str)
-               {
-                 case '\n':
-                     printf("\n");
-                     curr = 0;
-                     break;
-                 case '\t':
-                     do
-                        {
-                        printf(" ");
-                        curr++;
-                        }
-                     while((curr - col3) % tabsize != 0 && curr < col4);
-                 case ' ':
-                     if(*str == ' ')
-                        {
-                        curr++;
-                        printf(" ");
-                        }
-                     for(i = 1; str[i] && str[i] != ' ' && str[i] != '\n'
-                        && str[i] != '\t'; i++);
-                     if(curr + i - 1 >= col4)
-                        curr = col4;
-                     break;
-                default:
-                     printf("%c", *str);
-                     curr++;
-               }
-             if(curr >= col4)
-               {
-                 printf("\n");
-                 curr = 0;
-               }
-             str++;
-          }
-        }
-     printf("\n");
-}
-
-void gaa_help(void)
-{
-       printf("GnuTLS debug client\nUsage: gnutls-cli-debug [options] hostname\n\n\n");
-       __gaa_helpsingle('p', "port", "integer ", "The port to connect to.");
-       __gaa_helpsingle('d', "debug", "integer ", "Enable debugging");
-       __gaa_helpsingle('V', "verbose", "", "More verbose output");
-       __gaa_helpsingle('v', "version", "", "prints the program's version number");
-       __gaa_helpsingle('h', "help", "", "prints this help");
-
-#line 100 "gaa.skel"
-}
-/* Copy of C area */
-
-#line 104 "gaa.skel"
-/* GAA HEADER */
-#ifndef GAA_HEADER_POKY
-#define GAA_HEADER_POKY
-
-typedef struct _gaainfo gaainfo;
-
-struct _gaainfo
-{
-#line 29 "tls_test.gaa"
-       char *rest_args;
-#line 22 "tls_test.gaa"
-       int more_info;
-#line 19 "tls_test.gaa"
-       int debug;
-#line 16 "tls_test.gaa"
-       int pp;
-
-#line 114 "gaa.skel"
-};
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-    int gaa(int argc, char *argv[], gaainfo *gaaval);
-
-    void gaa_help(void);
-    
-    int gaa_file(const char *name, gaainfo *gaaval);
-    
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
-
-#line 135 "gaa.skel"
-
-/* C declarations */
-
-#define GAAERROR(x)    \
-{                   \
-gaa_error = 1;      \
-return x;        \
-}
-
-static char *gaa_current_option;
-static int gaa_error = 0;
-
-/* Generated by gaa */
-
-#include <string.h>
-#include <stdlib.h>
-
-
-#define GAA_OK                       -1
-
-#define GAA_ERROR_NOMATCH            0
-#define GAA_ERROR_NOTENOUGH_ARGS     1
-#define GAA_ERROR_INVALID_ARG        2
-#define GAA_ERROR_UNKNOWN            3
-
-#define GAA_NOT_AN_OPTION       0
-#define GAA_WORD_OPTION         1
-#define GAA_LETTER_OPTION       2
-#define GAA_MULTIPLE_OPTION     3
-
-#define GAA_REST                0
-#define GAA_NB_OPTION           5
-#define GAAOPTID_help  1
-#define GAAOPTID_version       2
-#define GAAOPTID_verbose       3
-#define GAAOPTID_debug 4
-#define GAAOPTID_port  5
-
-#line 168 "gaa.skel"
-
-#define GAA_CHECK1STR(a,b)      \
-if(a[0] == str[0])              \
-{                               \
-    gaa_current_option = a;     \
-    return b;                   \
-}
-
-#define GAA_CHECKSTR(a,b)                \
-if(strcmp(a,str) == 0)                   \
-{                                        \
-    gaa_current_option = a;              \
-    return b;                            \
-}
-
-#define GAA_TESTMOREARGS                                                  \
-if(!OK)                                                                     \
-{                                  \
-while((gaa_last_non_option != gaa_index) && (gaa_arg_used[gaa_index] == 1)) \
-    gaa_index++;                                                            \
-if(gaa_last_non_option == gaa_index)                                        \
-    return GAA_ERROR_NOTENOUGH_ARGS; \
-}
-
-#define GAA_TESTMOREOPTIONALARGS                                                  \
-if(!OK) \
-{ \
-while((gaa_last_non_option != gaa_index) && (gaa_arg_used[gaa_index] == 1)) \
-    gaa_index++;                                                            \
-if(gaa_last_non_option == gaa_index)                                        \
-    OK = 1; \
-}
-
-#define GAA_FILL_2ARGS(target, func)           \
-target = func(GAAargv[gaa_index]);       \
-gaa_arg_used[gaa_index] = 1;             \
-if(gaa_error == 1)                       \
-{                                        \
-    gaa_error = 0;                       \
-    return GAA_ERROR_INVALID_ARG;        \
-} 
-
-
-
-#define GAA_FILL(target, func, num)           \
-if(!OK) \
-{ \
-target = func(GAAargv[gaa_index]);       \
-gaa_arg_used[gaa_index] = 1;             \
-if(gaa_error == 1)                       \
-{                                        \
-    gaa_error = 0;                       \
-    return GAA_ERROR_INVALID_ARG;        \
-} \
-num = 1;  \
-} \
-else \
-{ \
-num = 0; \
-}
-
-#define GAA_LIST_FILL(target, func, type ,num)                      \
-if(!OK) \
-{ \
-num = 0;                                                            \
-target = NULL;                                                      \
-if ( gaa_last_non_option - gaa_index > 0)                           \
-  target = gaa_malloc((gaa_last_non_option - gaa_index) * sizeof(type));\
-for(; gaa_index < gaa_last_non_option; gaa_index++)                 \
-{                                                                   \
-    if(gaa_arg_used[gaa_index] == 0)                                \
-    {                                                               \
-        GAA_FILL_2ARGS(target[num], func);                          \
-        num++;                                                      \
-    }                                                               \
-}                                                                   \
-if(num == 0)                                                        \
-    return GAA_ERROR_NOTENOUGH_ARGS; \
-}
-
-#define GAA_OPTIONALLIST_FILL(target, func, type ,num)                      \
-if(!OK) \
-{ \
-num = 0;                                                            \
-target = NULL;                                                      \
-if ( gaa_last_non_option - gaa_index > 0)                           \
-  target = gaa_malloc((gaa_last_non_option - gaa_index) * sizeof(type));\
-for(; gaa_index < gaa_last_non_option; gaa_index++)                 \
-{                                                                   \
-    if(gaa_arg_used[gaa_index] == 0)                                \
-    {                                                               \
-        GAA_FILL_2ARGS(target[num], func);                                \
-        num++;                                                      \
-    }                                                               \
-} \
-}
-
-#define GAA_OBLIGAT(str)                                            \
-k = 0;                                                              \
-for(i = 0; i < strlen(str); i++)                                    \
-{                                                                   \
-    j = gaa_get_option_num(str + i, GAA_LETTER_OPTION);           \
-    if(j == GAA_ERROR_NOMATCH)                                       \
-    {                                                               \
-        printf("Error: invalid 'obligat' set\n");                  \
-        exit(-1);                                                   \
-    }                                                               \
-    if(opt_list[j] == 1)                                            \
-        k = 1;                                                      \
-}                                                                    \
-if(k == 0)                                                            \
-{                                                                      \
-    if(strlen(str) == 1)                                                \
-        printf("You must give the -%s option\n", str);                     \
-    else                                                                  \
-        printf("You must give at least one option of '%s'\n", str);          \
-    return 0;         \
-}
-        
-#define GAA_INCOMP(str)                                                \
-k = 0;                                                              \
-for(i = 0; i < strlen(str); i++)                                    \
-{                                                                   \
-    j = gaa_get_option_num(str + i, GAA_LETTER_OPTION);           \
-    if(j == GAA_ERROR_NOMATCH)                                      \
-    {                                                               \
-        printf("Error: invalid 'obligat' set\n");                  \
-        exit(-1);                                                   \
-    }                                                               \
-    if(opt_list[j] == 1)                                            \
-        k++;                                                      \
-}                   \
-if(k > 1)                                                            \
-{                                                                      \
-    printf("The options '%s' are incompatible\n", str);              \
-    return 0;                                                          \
-}
-        
-
-static char **GAAargv;
-static int GAAargc;
-static char *gaa_arg_used;
-static int gaa_processing_file = 0;
-static int inited = 0;
-
-static int gaa_getint(char *arg)
-{
-    int tmp;
-    char a;
-    if(sscanf(arg, "%d%c", &tmp, &a) < 1)
-    {
-        printf("Option %s: '%s' isn't an integer\n", gaa_current_option, arg);
-        GAAERROR(-1);
-    }
-    return tmp;
-}
-
-
-static char* gaa_getstr(char *arg)
-{
-    return arg;
-}
-
-/* option structures */
-
-struct GAAOPTION_debug 
-{
-       int arg1;
-       int size1;
-};
-
-struct GAAOPTION_port 
-{
-       int arg1;
-       int size1;
-};
-#define GAA_REST_EXISTS
-
-struct GAAREST
-{
-       char* arg1;
-       int size1;
-};
-         
-#line 349 "gaa.skel"
-static int gaa_is_an_argument(char *str)
-{
-#ifdef GAA_WIN32
-    if(str[0] == '/' && str[1] != 0)
-       return GAA_MULTIPLE_OPTION;
-#endif
-    if(str[0] != '-')
-        return GAA_NOT_AN_OPTION;
-    if(str[1] == 0)
-        return GAA_NOT_AN_OPTION;
-    if(str[1] == '-')
-    {
-        if(str[2] != 0)
-            return GAA_WORD_OPTION;
-        else
-            return GAA_NOT_AN_OPTION;
-    }
-    if(str[2] == 0)
-        return GAA_LETTER_OPTION;
-    else
-        return GAA_MULTIPLE_OPTION;
-}
-
-static int gaa_get_option_num(char *str, int status)
-{
-    switch(status)
-        {
-        case GAA_LETTER_OPTION:
-                       GAA_CHECK1STR("d", GAAOPTID_debug);
-                       GAA_CHECK1STR("p", GAAOPTID_port);
-        case GAA_MULTIPLE_OPTION:
-#line 375 "gaa.skel"
-                       GAA_CHECK1STR("h", GAAOPTID_help);
-                       GAA_CHECK1STR("v", GAAOPTID_version);
-                       GAA_CHECK1STR("V", GAAOPTID_verbose);
-
-#line 277 "gaa.skel"
-        break;
-        case GAA_WORD_OPTION:
-                       GAA_CHECKSTR("help", GAAOPTID_help);
-                       GAA_CHECKSTR("version", GAAOPTID_version);
-                       GAA_CHECKSTR("verbose", GAAOPTID_verbose);
-                       GAA_CHECKSTR("debug", GAAOPTID_debug);
-                       GAA_CHECKSTR("port", GAAOPTID_port);
-
-#line 281 "gaa.skel"
-       break;
-        default: break;
-        }
-    return GAA_ERROR_NOMATCH;
-}
-
-static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
-{
-    int OK = 0;
-    int gaa_last_non_option;
-       struct GAAOPTION_debug GAATMP_debug;
-       struct GAAOPTION_port GAATMP_port;
-
-#line 393 "gaa.skel"
-#ifdef GAA_REST_EXISTS
-    struct GAAREST GAAREST_tmp;
-#endif
-
-    opt_list[gaa_num] = 1;
-    
-    for(gaa_last_non_option = gaa_index;
-        (gaa_last_non_option != GAAargc) && (gaa_is_an_argument(GAAargv[gaa_last_non_option]) == GAA_NOT_AN_OPTION);
-        gaa_last_non_option++);
-
-    if(gaa_num == GAA_REST)
-    {
-        gaa_index = 1;
-        gaa_last_non_option = GAAargc;
-    }
-    
-    switch(gaa_num)
-    {
-       case GAAOPTID_help:
-       OK = 0;
-#line 26 "tls_test.gaa"
-{ gaa_help(); exit(0); ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_version:
-       OK = 0;
-#line 25 "tls_test.gaa"
-{ tls_test_version(); exit(0); ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_verbose:
-       OK = 0;
-#line 23 "tls_test.gaa"
-{ gaaval->more_info += 1 ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_debug:
-       OK = 0;
-               GAA_TESTMOREARGS;
-               GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1);
-               gaa_index++;
-#line 20 "tls_test.gaa"
-{ gaaval->debug = GAATMP_debug.arg1 ;};
-
-               return GAA_OK;
-               break;
-       case GAAOPTID_port:
-       OK = 0;
-               GAA_TESTMOREARGS;
-               GAA_FILL(GAATMP_port.arg1, gaa_getint, GAATMP_port.size1);
-               gaa_index++;
-#line 17 "tls_test.gaa"
-{ gaaval->pp = GAATMP_port.arg1 ;};
-
-               return GAA_OK;
-               break;
-       case GAA_REST:
-               GAA_TESTMOREARGS;
-               GAA_FILL(GAAREST_tmp.arg1, gaa_getstr, GAAREST_tmp.size1);
-               gaa_index++;
-#line 30 "tls_test.gaa"
-{ gaaval->rest_args = GAAREST_tmp.arg1; ;};
-
-               return GAA_OK;
-               break;
-
-#line 413 "gaa.skel"
-    default: break;
-    }
-    return GAA_ERROR_UNKNOWN;
-}
-
-int gaa(int argc, char **argv, gaainfo *gaaval)
-{
-    int tmp1, tmp2;
-    int l;
-    size_t i, j;
-    char *opt_list;
-
-    i = 0;
-
-    GAAargv = argv;
-    GAAargc = argc;
-
-    opt_list = (char*) gaa_malloc(GAA_NB_OPTION + 1);
-
-    for(l = 0; l < GAA_NB_OPTION + 1; l++)
-        opt_list[l] = 0;
-    /* initialization */
-    if(inited == 0)
-    {
-
-#line 32 "tls_test.gaa"
-{ gaaval->rest_args=NULL; gaaval->pp = 443; gaaval->more_info = 0; ;};
-
-    }
-    inited = 1;
-#line 438 "gaa.skel"
-    gaa_arg_used = NULL;
-
-    if (argc > 0) {
-      gaa_arg_used = gaa_malloc(argc * sizeof(char));
-    }
-
-    for(l = 1; l < argc; l++)
-        gaa_arg_used[l] = 0;
-    for(l = 1; l < argc; l++)
-    {
-        if(gaa_arg_used[l] == 0)
-        {
-            j = 0;
-            tmp1 = gaa_is_an_argument(GAAargv[l]);
-            switch(tmp1)
-            {
-            case GAA_WORD_OPTION:
-                j++;
-            case GAA_LETTER_OPTION:
-                j++;
-                tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
-                if(tmp2 == GAA_ERROR_NOMATCH)
-                {
-                    printf("Invalid option '%s'\n", argv[l]+j);
-                    return 0;
-                }
-                switch(gaa_try(tmp2, l+1, gaaval, opt_list))
-                {
-                case GAA_ERROR_NOTENOUGH_ARGS:
-                    printf("'%s': not enough arguments\n",gaa_current_option);
-                    return 0;
-                case GAA_ERROR_INVALID_ARG:
-                    printf("Invalid arguments\n");
-                    return 0;
-                case GAA_OK:
-                    break;
-                default:
-                    printf("Unknown error\n");
-                }
-                gaa_arg_used[l] = 1;
-                break;
-            case GAA_MULTIPLE_OPTION:
-                for(j = 1; j < strlen(argv[l]); j++)
-                {
-                    tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
-                    if(tmp2 == GAA_ERROR_NOMATCH)
-                    {
-                        printf("Invalid option '%c'\n", *(argv[l]+j));
-                        return 0;
-                    }
-                    switch(gaa_try(tmp2, l+1, gaaval, opt_list))
-                    {
-                    case GAA_ERROR_NOTENOUGH_ARGS:
-                        printf("'%s': not enough arguments\n",gaa_current_option);
-                        return 0;
-                    case GAA_ERROR_INVALID_ARG:
-                        printf("Invalid arguments\n");
-                        return 0;
-                    case GAA_OK:
-                        break;
-                    default:
-                        printf("Unknown error\n");
-                    }
-                }
-                gaa_arg_used[l] = 1;
-                break;
-            default: break;
-            }
-        }
-    }
-if(gaa_processing_file == 0)
-{
-
-#line 507 "gaa.skel"
-#ifdef GAA_REST_EXISTS
-    switch(gaa_try(GAA_REST, 1, gaaval, opt_list))
-    {
-    case GAA_ERROR_NOTENOUGH_ARGS:
-        printf("Rest: not enough arguments\n");
-        return 0;
-    case GAA_ERROR_INVALID_ARG:
-        printf("Invalid arguments\n");
-        return 0;
-    case GAA_OK:
-        break;
-    default:
-        printf("Unknown error\n");
-    }
-#endif
-}
-    for(l = 1; l < argc; l++)
-    {
-        if(gaa_arg_used[l] == 0)
-        {
-            printf("Too many arguments\n");
-            return 0;
-        }
-    }
-    free(gaa_arg_used);
-    free(opt_list);
-    return -1;
-}
-
-struct gaastrnode
-{
-    char *str;
-    struct gaastrnode *next;
-};
-
-typedef struct gaastrnode gaa_str_node;
-
-static int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc)
-{
-    int pos_ini;
-    int a;
-    int i = 0, len = 0, newline = 0;
-
-    if(argc == 1) {
-        newline = 1;
-        len = 2;
-    }
-    
-    a = fgetc( file);
-    if (a == EOF) return 0;
-
-    while(a == ' ' || a == 9 || a == '\n')
-    {
-        if(a == '\n')
-        {
-            newline=1;
-            len = 2;
-        }
-        a = fgetc( file);
-        if (a == EOF) return 0;
-    }
-
-    pos_ini = ftell(file) - 1;
-
-    while(a != ' ' && a != 9 && a != '\n')
-    {
-
-        len++;
-        a = fgetc( file);
-        if(a==EOF) return 0; /* a = ' '; */
-    }
-
-    len += 1;
-    tmp_str->str = gaa_malloc((len) * sizeof(char));
-
-    if(newline == 1)
-    {
-        tmp_str->str[0] = '-';
-        tmp_str->str[1] = '-';
-        i = 2;
-    }
-    else
-    {
-        i = 0;
-    }
-
-    fseek(file,pos_ini, SEEK_SET);
-    do
-    {
-        a = fgetc( file);
-
-        if (a == EOF) {
-            i+=2;
-            break;
-        }
-        tmp_str->str[i] = a;
-        i++;
-    }
-    while(a != ' ' && a != 9 && a != '\n' && i < len);
-
-    tmp_str->str[i - 1] = 0;
-
-    fseek(file,- 1, SEEK_CUR);
-/*    printf("%d\n", ftell(file)); */
-    
-    return -1;
-}
-
-int gaa_file(const char *name, gaainfo *gaaval)
-{
-    gaa_str_node *first_str, **tmp_str, *tmp_str2;
-    int rval, i;
-    char **argv;
-    int argc = 0;
-    FILE *file;
-
-    gaa_processing_file = 1;
-    
-    if((file = fopen(name, "r")) == NULL)
-    {
-        printf("Couldn't open '%s' configuration file for reading\n", name);
-        return 1;
-    }
-    
-    tmp_str = &first_str;
-    do
-    {
-        argc++;
-        *tmp_str = gaa_malloc(sizeof(gaa_str_node));
-
-        (*tmp_str)->str = NULL;
-        (*tmp_str)->next = NULL;
-
-        rval = gaa_internal_get_next_str(file, *tmp_str, argc);
-        tmp_str = &((*tmp_str)->next);
-    }
-    while(rval == -1);
-    
-    if(rval == 1)
-        return 0;
-    
-    argv = gaa_malloc((1 + argc) * sizeof(char*));
-
-    tmp_str2 = first_str;
-    argv[0] = "cfg";
-    for(i = 1; i < argc; i++)
-    {
-        argv[i] = tmp_str2->str;
-        tmp_str2 = tmp_str2->next;
-    }
-
-    rval = gaa(argc, argv, gaaval);
-    gaa_processing_file = 0;
-    return rval;
-}
diff --git a/src/tls_test-gaa.h b/src/tls_test-gaa.h
deleted file mode 100644 (file)
index ec9b98e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-
-#line 104 "gaa.skel"
-/* GAA HEADER */
-#ifndef GAA_HEADER_POKY
-#define GAA_HEADER_POKY
-
-typedef struct _gaainfo gaainfo;
-
-struct _gaainfo
-{
-#line 29 "tls_test.gaa"
-       char *rest_args;
-#line 22 "tls_test.gaa"
-       int more_info;
-#line 19 "tls_test.gaa"
-       int debug;
-#line 16 "tls_test.gaa"
-       int pp;
-
-#line 114 "gaa.skel"
-};
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-    int gaa(int argc, char *argv[], gaainfo *gaaval);
-
-    void gaa_help(void);
-    
-    int gaa_file(const char *name, gaainfo *gaaval);
-    
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
index 18132d19197246688ac7609c5528e85ac230efda..efef925842c1254a7ac689c36900c25ed3dc0701 100644 (file)
 #endif
 #include <tests.h>
 #include <common.h>
-#include <tls_test-gaa.h>
+#include <cli-debug-args.h>
 
 /* Gnulib portability files. */
 #include <progname.h>
 #include <version-etc.h>
 #include "sockets.h"
 
+static void cmd_parser (int argc, char **argv);
+
 #define ERR(err,s) if (err==-1) {perror(s);return(1);}
 #define MAX_BUF 4096
 
@@ -49,7 +51,7 @@ const char *hostname = NULL;
 int port;
 int record_max_size;
 int fingerprint;
-static int debug;
+static int debug = 0;
 
 gnutls_srp_client_credentials_t srp_cred;
 gnutls_anon_client_credentials_t anon_cred;
@@ -165,8 +167,6 @@ static const TLS_TEST tls_tests[] = {
 static int tt = 0;
 const char *ip;
 
-static void gaa_parser (int argc, char **argv);
-
 int
 main (int argc, char **argv)
 {
@@ -178,7 +178,7 @@ main (int argc, char **argv)
   struct addrinfo hints, *res, *ptr;
 
   set_program_name (argv[0]);
-  gaa_parser (argc, argv);
+  cmd_parser(argc, argv);
 
 #ifndef _WIN32
   signal (SIGPIPE, SIG_IGN);
@@ -317,26 +317,31 @@ main (int argc, char **argv)
   return 0;
 }
 
-static gaainfo info;
-void
-gaa_parser (int argc, char **argv)
+static void cmd_parser (int argc, char **argv)
 {
-  if (gaa (argc, argv, &info) != -1)
-    {
-      fprintf (stderr,
-               "Error in the arguments. Use the -h or --help parameters to get more info.\n");
-      exit (1);
-    }
+  const char* rest = NULL;
+  int optct = optionProcess( &gnutls_cli_debugOptions, argc, argv);
+  argc -= optct;
+  argv += optct;
+  
+  if (rest == NULL && argc > 0)
+    rest = argv[0];
+
+  if (HAVE_OPT(PORT))
+    port = OPT_VALUE_PORT;
+  else
+    port = 443;
 
-  port = info.pp;
-  if (info.rest_args == NULL)
+  if (rest == NULL)
     hostname = "localhost";
   else
-    hostname = info.rest_args;
+    hostname = rest;
 
-  debug = info.debug;
+  if (HAVE_OPT(DEBUG))
+    debug = OPT_VALUE_DEBUG;
 
-  verbose = info.more_info;
+  if (HAVE_OPT(VERBOSE))
+    verbose++;
 
 }
 
diff --git a/src/tls_test.gaa b/src/tls_test.gaa
deleted file mode 100644 (file)
index 64a3a96..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#{
-
-/* C declarations */
-
-#include <config.h>
-#ifdef _WIN32
-# include <io.h>
-#endif
-
-void tls_test_version(void);
-
-#}
-
-helpnode "GnuTLS debug client\nUsage: gnutls-cli-debug [options] hostname\n\n"
-
-#int pp;
-option (p, port) INT "integer" { $pp = $1 } "The port to connect to."
-
-#int debug;
-option (d, debug) INT "integer" { $debug = $1 } "Enable debugging" 
-
-#int more_info;
-option (V, verbose) { $more_info += 1 } "More verbose output"
-
-option (v, version) { tls_test_version(); exit(0); } "prints the program's version number"
-option (h, help) { gaa_help(); exit(0); } "prints this help"
-
-
-#char *rest_args;
-rest STR "hostname" { $rest_args = $1; }
-
-init { $rest_args=NULL; $pp = 443; $more_info = 0; }