[= -*- Mode: texinfo -*-
AutoGen5 Template
# This file is part of AutoGen.
# AutoGen Copyright (C) 1992-2018 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 .
=]
@page
@node AutoOpts
@chapter Automated Option Processing
@cindex autoopts
AutoOpts [=
(make-tmp-dir)
(out-push-new)
=]
test ${#AGexe} -eq 0 -o ${#top_srcdir} -eq 0 -o ${top_builddir} -eq 0 && \
die "AGexe, top_srcdir and top_builddir must be set"
ag_cmd="${AGexe} -L${top_srcdir}/autoopts/tpl"
test "X${top_srcdir}" = "X${top_builddir}" || \
ag_cmd="${ag_cmd} -L${top_builddir}/autoopts/tpl"
readonly ag_cmd
run_ag() {
echo ${ag_cmd} "$@" >&2
${ag_cmd} "$@"
}
eval "`egrep '^AO_[A-Z]*=' ${top_srcdir}/VERSION`" 2> /dev/null
echo ${AO_CURRENT}.${AO_REVISION}
[=
(shell (out-pop #t))
=] is bundled with AutoGen. It is a tool that virtually eliminates the
hassle of processing options and keeping man pages, info docs and usage text
up to date. This package allows you to specify several program attributes,
thousands of option types and many option attributes. From this, it then
produces all the code necessary to parse and handle the command line and
configuration file options, and the documentation that should go with your
program as well.
[=
INVOKE get-text tag = autoopts =][=
(out-push-new (string-append tmp-dir "/check.def" ))
=]
AutoGen Definitions options;
prog-name = check;
prog-title = "Checkout Automated Options";
long-opts;
gnu-usage; /* GNU style preferred to default */
main = { main-type = shell-process; };
flag = {
name = check-dirs;
value = L; /* flag style option character */
arg-type = string; /* option argument indication */
max = NOLIMIT; /* occurrence limit (none) */
stack-arg; /* save opt args in a stack */
descrip = "Checkout directory list";
doc = 'name of each directory that is to be "checked out".';
};
flag = {
name = show_defs;
descrip = "Show the definition tree";
disable = dont; /* mark as enable/disable type */
/* option. Disable as `dont-' */
doc = 'disable, if you do not want to see the tree.';
};
[= (texi-escape-encode (out-pop #t)) \=]
@end example
@node quick ao build
@subsection Build the example options
This program will produce a program that digests its options and
writes the values as shell script code to stdout.
Run the following short script to produce this program:[= #
Developer note: the following only works when AutoGen has been installed.
Since this may be being built on a system where it has not been installed,
the code below ensures we are running out tools out of the build directory
=]
@example
[=
(out-push-new (string-append tmp-dir "/mk-check.sh" ))
\=]
base=check
BASE=`echo $base | tr '[a-z-]' '[A-Z_]'`
cflags="-DTEST_${BASE} `autoopts-config cflags`"
ldflags="`autoopts-config ldflags`"
autogen ${base}.def
cc -o ${base} -g ${cflags} ${base}.c ${ldflags}
./${base} --help
[= (texi-escape-encode (out-pop #t)) \=]
@end example
@node quick ao help
@subsection Example option help text
Running the build commands yields:
@example
[= (out-push-new) \=]
base=check
cd ${tmp_dir}
(
PS4='>ck> '
BASH_XTRACEFD=2
exec 2> ${base}-msg.log 1>&2
set -x
test -f ${base}.def || die "cannot locate ${base}.def"
test ! -f ${base} || rm -f ${base}
echo "include = '#include \"compat/compat.h\"';" >> ${base}.def
f='@="@="'`echo ${INCLUDES} ${CFLAGS}`' @'
sed -e "s@^cc @${CC:-cc} -include ${top_builddir}/config.h @" \
-e '/^cflags="/s'"${f}" \
-e 's@^autogen @run_ag @' \
mk-${base}.sh > mk-${base}
. ./mk-${base}
)
test -x ./${base} || {
cat mk-${base}
printf '\n\nFAILURE LOG:\n\n'
cat ${base}-msg.log
tar czf /tmp/ck-fail.tgz .
die cannot create ${base} program
} >&2
./${base} --help | sed 's/\t/ /g'
[=
(texi-escape-encode (shell (out-pop #t)))
=]
@end example
[=
INVOKE get-text tag = autoopts-main
=]
Here is an example program that uses the following set of definitions:
@example
[=
(out-push-new (string-append tmp-dir "/default-test.def" ))
=]AutoGen Definitions options;
prog-name = default-test;
prog-title = 'Default Option Example';
homerc = '$$/../share/default-test', '$HOME', '.';
environrc;
long-opts;
gnu-usage;
usage-opt;
version = '1.0';
main = {
main-type = shell-process;
};
#define DEBUG_FLAG
#define WARN_FLAG
#define WARN_LEVEL
#define VERBOSE_FLAG
#define VERBOSE_ENUM
#define DRY_RUN_FLAG
#define OUTPUT_FLAG
#define INPUT_FLAG
#define DIRECTORY_FLAG
#define INTERACTIVE_FLAG
#include stdoptions.def
[=
(texi-escape-encode (out-pop #t))
=]@end example
@noindent
Running a few simple commands on that definition file:
@example
autogen default-test.def
copts="-DTEST_DEFAULT_TEST_OPTS `autoopts-config cflags`"
lopts="`autoopts-config ldflags`"
cc -o default-test $@{copts@} default-test.c $@{lopts@}
@end example
@noindent
Yields a program which, when run with @file{--help}, prints out:
@example
[= (out-push-new) \=]
set -x
log_file=${tmp_dir}/ao-doc-log
exec 7>&2 ; exec 2>> ${log_file}
TOPDIR=`cd ${top_builddir} >/dev/null ; pwd`
OPTDIR=${TOPDIR}/autoopts
{
cd ${tmp_dir}
chmod 666 *.def
echo 'config-header = "config.h";' >> default-test.def
HOME=${tmp_dir} run_ag default-test.def
test -f default-test.c || die 'NO default-test.c PROGRAM'
opts="-o default-test -DTEST_DEFAULT_TEST_OPTS ${INCLUDES}"
${CC:-cc} ${CFLAGS} ${opts} default-test.c ${LIBS} || \
rm -f ./default-test
test -x ./default-test || {
exec 2>&7
fail_text=`cat $log_file`$'\n\nprogram:\n'`cat default-test.c`
die 'NO default-test EXECUTABLE
'"$fail_text"'
=== END FAIL TEXT'
}
} >&2
HOME=${tmp_dir} ${tmp_dir}/default-test --help | \
sed 's, , ,g;s,\([@{}]\),@\1,g'
exec 2>&7 7>&-
[=
(shell (out-pop #t))
=]
@end example
[=
INVOKE get-text tag = autoopts-api
=]
[=`
f=../autoopts/libopts.texi
test -f $f || {
f=${top_srcdir}/autoopts/libopts.texi
test -f $f || die "Cannot locate libopts.texi in $f"
}
cat $f
`=]
[=
INVOKE get-text tag = "autoopts-data"
=]
@noindent
Doing so with getdefs' option definitions yields this sample-getdefsrc file.
I tend to be wordy in my @code{doc} attributes:
@example
[= (texi-escape-encode (shell "
cd ${tmp_dir}
run_ag -Trc-sample.tpl ${top_srcdir}/getdefs/opts.def >/dev/null
test -f sample-getdefsrc || die did not create sample-getdefsrc
cat sample-getdefsrc
" )) =]
@end example
[=
INVOKE get-text tag = "ao-data1"
=]
@example[=
(out-push-new (string-append tmp-dir "/hello.c"))
\=]
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
#include
#endif
#include
int main(int argc, char ** argv) {
char const * greeting = "Hello";
char const * greeted = "World";
tOptionValue const * pOV = configFileLoad("hello.conf");
if (pOV != NULL) {
const tOptionValue* pGetV = optionGetValue(pOV, "greeting");
if ( (pGetV != NULL)
&& (pGetV->valType == OPARG_TYPE_STRING))
greeting = strdup(pGetV->v.strVal);
pGetV = optionGetValue(pOV, "personalize");
if (pGetV != NULL) {
struct passwd * pwe = getpwuid(getuid());
if (pwe != NULL)
greeted = strdup(pwe->pw_gecos);
}
optionUnloadNested(pOV); /* deallocate config data */
}
printf("%s, %s!\n", greeting, greeted);
return 0;
}
[= (texi-escape-encode (out-pop #t)) \=]
@end example
@noindent
With that text in a file named ``hello.c'', this short script:
@example
cc -o hello hello.c `autoopts-config cflags ldflags`
./hello
echo 'greeting Buzz off' > hello.conf
./hello
echo personalize > hello.conf
./hello
@end example
@noindent
will produce the following output:
@example
[= (texi-escape-encode (shell "
cd ${tmp_dir}
${CC:-cc} -o hello hello.c ${CFLAGS} ${LIBS} ${LDFLAGS} || \
die cannot compile hello
./hello
echo 'greeting Buzz off' > hello.conf
./hello
echo personalize > hello.conf
./hello"
)) =]
@end example
[=
INVOKE get-text tag = "ao-data2"
=]
[=
(out-push-new)
=](
exec 4>&2 2> ${tmp_dir}/err-test-log.txt
BASH_XTRACEFD=2
PS4='>etl> '
set -x
cd ${top_builddir}/autoopts/test || \
die "cannot cd into ${top_builddir}/autoopts/test"
VERBOSE=true AUTOGEN_TRACE=every AUTOGEN_TRACE_OUT=">>$PWD/ag-log.txt"
export VERBOSE AUTOGEN_TRACE AUTOGEN_TRACE_OUT
${MAKE:-make} check TESTS=errors.test 1>&2 || :
if test ! -x errors-testd/errors
then
exec 2>&4
cat ${tmp_dir}/err-test-log.txt >&2
die "no error usage in $PWD/errors-testd"
fi
cat <<-EOF
Here is the usage output example from AutoOpts error handling
tests. The option definition has argument reordering enabled:
@example
EOF
./errors-testd/errors -? | sed 's, , ,g;s,\([@{}]\),@\1,g'
cmd='errors operand1 -s first operand2 -X -- -s operand3'
cat <<-EOF
@end example
Using the invocation,
@example
test-${cmd}
@end example
you get the following output for your shell script to evaluate:
@example
`./errors-testd/${cmd}`
@end example
EOF
)[=
(shell (out-pop #t))
=]
@node script-parser
@subsection Parsing with a Portable Script
If you had used @code{test-main = optionParseShell} instead, then you can,
at this point, merely run the program and it will write the parsing
script to standard out. You may also provide this program with command
line options to specify the shell script file to create or edit, and you
may specify the shell program to use on the first shell script line.
That program's usage text would look something like the following
and the script parser itself would be very verbose:
@example
[= `
log=${tmp_dir}/../genshellopt.log
(
set -x
opts="-o genshellopt -DTEST_GETDEFS_OPTS ${INCLUDES}"
exec 3> ${tmp_dir}/genshellopt.def
cat ${top_srcdir}/getdefs/opts.def >&3
echo "test_main = 'optionParseShell';" >&3
echo 'config-header = "config.h";' >&3
exec 3>&-
cd ${tmp_dir}
HOME='' run_ag -t40 genshellopt.def
test $? -eq 0 || die "autogen failed to create genshellopt.c - See ${log}"
${CC} ${CFLAGS} ${opts} genshellopt.c ${LIBS}
test $? -eq 0 || {
head -n 50000 genshellopt.[ch]
die "could not compile genshellopt.c - See ${log}"
}
) > ${log} 2>&1
test -x ${tmp_dir}/genshellopt || \
die "NO GENSHELLOPT PROGRAM - See ${log}"
${tmp_dir}/genshellopt --help > ${tmp_dir}/genshellopt.hlp
${tmp_dir}/genshellopt -o ${tmp_dir}/genshellopt.sh || \
die cannot create ${tmp_dir}/genshellopt.sh
sedcmd='s,\t, ,g;s,\\([@{}]\\),@\\1,g'
sed "${sedcmd}" ${tmp_dir}/genshellopt.hlp
cat <<- \_EOF_
@end example
@noindent
Resulting in the following script:
@example
_EOF_
sed "${sedcmd}" ${tmp_dir}/genshellopt.sh
` =]
@end example
[=
INVOKE get-text tag = autoinfo
=]