diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-11-27 15:05:18 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-12-07 20:27:03 +0200 |
commit | 9097d5294cf62c4cb7cd5e352e1d0c42d3c04d81 (patch) | |
tree | 4e40c0af4dae891f38cfc466edcc7e0a3331b267 /build-aux | |
parent | 1202780fd92ff9fc2854bfa2d0ab0c39169eabd5 (diff) | |
download | grecs-9097d5294cf62c4cb7cd5e352e1d0c42d3c04d81.tar.gz grecs-9097d5294cf62c4cb7cd5e352e1d0c42d3c04d81.tar.bz2 |
Revise getopt.m4
Diffstat (limited to 'build-aux')
-rw-r--r-- | build-aux/getopt.m4 | 240 |
1 files changed, 177 insertions, 63 deletions
diff --git a/build-aux/getopt.m4 b/build-aux/getopt.m4 index 93d81df..85e930e 100644 --- a/build-aux/getopt.m4 +++ b/build-aux/getopt.m4 @@ -1,5 +1,5 @@ dnl This file is part of grecs -dnl Copyright (C) 2007-2016 Sergey Poznyakoff +dnl Copyright (C) 2007-2018 Sergey Poznyakoff dnl dnl Grecs is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -17,6 +17,27 @@ divert(-1) changequote([<,>]) changecom(/*,*/) +dnl Diversion channels +define([<__DIV_OPTKEYS__>],1)dnl option keys +define([<__DIV_OPTDECL__>],2)dnl struct option declarations +define([<__DIV_HELPDECL__>],3)dnl grecs_opthelp declarations +define([<__DIV_SWITCH__>],4)dnl switch statement body +define([<__DIV_STATIC__>],5)dnl module static data + +dnl Special macros that can be set during expansion +pushdef([<__GETOPT_DEFINED__>]) +pushdef([<__OPTIONS_END_DEFINED__>]) +pushdef([<__GETOPT_LASTOPT_LABEL__>]) + +define([<__GETOPT_LONG_TAG>]) +define([<__GETOPT_SHORT_TAG>]) + +define([<WITH_DIVERSION>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl +pushdef([<__GETOPT_DIVERSION__>],divnum)dnl +divert([<$1>])$2dnl +divert(__GETOPT_DIVERSION__)dnl +popdef([<__GETOPT_DIVERSION__>])>])>]) + dnl _getopt_mangle_option(NAME) dnl --------------------------- dnl Convert NAME to a valid m4 identifier, by replacing invalid characters @@ -33,7 +54,7 @@ define([<_getopt_set_option>], [<_getopt_mangle_option(\1),[<\2>]>]))>])>]) dnl _getopt_get_option(NAME[,DEFAULT]) -dnl ------------------------------ +dnl ---------------------------------- define([<_getopt_get_option>], [<_getopt_if_option_set($1,[<indir(_getopt_mangle_option($1))>],[<$2>])>]) @@ -44,7 +65,7 @@ define([<_getopt_if_option_set>], [<ifdef(_getopt_mangle_option([<$1>]),[<$2>],[<$3>])>]) dnl _getopt_if_option_null(NAME,IF-NULL,IF-NOT-NULL) -dnl --------------------------------------------- +dnl ------------------------------------------------ dnl Check if option NAME is set. define([<_getopt_if_option_null>], [<ifelse(indir(_getopt_mangle_option([<$1>])),,[<$2>],[<$3>])>]) @@ -61,7 +82,7 @@ define([<_getopt_option_switch>], [<_getopt_option_switch(shift(shift($@)))>])>])>]) dnl _getopt_if_option_val(NAME,val,IF-TRUE,IF-FALSE) -dnl --------------------------------------------- +dnl ------------------------------------------------ dnl Check if option NAME is set. define([<_getopt_if_option_val>], [<ifelse(_getopt_get_option([<$1>]),[<$2>],[<$3>],[<$4>])>]) @@ -89,34 +110,39 @@ define([<_getopt_set_options>], _getopt_set_options(shift($@))>])>]) dnl __getopt_format_authors(name[,name...]) -dnl ------------------------------ +dnl --------------------------------------- define([<__getopt_format_authors>],dnl [<ifelse([<$1>],,NULL,[<"$1", __getopt_format_authors(shift($@))>])>]) dnl __getopt_upcase(ARGS...) +dnl ------------------------ dnl Concatenate and convert ARGS to upper case. dnl define([<__getopt_upcase>], [<translit([<$*>], [<a-z>], [<A-Z>])>]) dnl __getopt_concat(ARGS...) +dnl ------------------------ dnl Concatenate arguments, inserting ", " between each pair of them. dnl define([<__getopt_concat>],[<ifelse([<$#>],1,[<$1>],[<$1, __getopt_concat(shift($@))>])>]) dnl __getopt_flushleft(ARGS...) +dnl --------------------------- dnl Concatenate ARGS and remove any leading whitespace dnl define([<__getopt_flushleft>], [<patsubst([<__getopt_concat($*)>], [<^[ ]+>])>]) dnl __getopt_chop(ARGS...) +dnl ---------------------- dnl Concatenate ARGS and remove any trailing whitespace dnl define([<__getopt_chop>], [<patsubst([<$*>], [<[ ]+$>])>]) dnl __getopt_escape(ARGS...) +dnl ------------------------ dnl Concatenate ARGS and escape any occurrences of double-quotes with dnl backslashes. dnl @@ -124,6 +150,7 @@ define([<__getopt_escape>], [<patsubst([<__getopt_concat($*)>],[<[\"]>],[<\\\&>])>]) dnl __getopt_prep(ARG) +dnl ------------------ dnl Prepare ARG for including in C strings: replace newlines and any dnl preceding and following whitespace by a single space character, remove dnl leading whitespace, and escape double-quotes. @@ -133,46 +160,56 @@ define([<__getopt_prep>], +[ ]*>],[< >])))>]) dnl __GETOPT_SHORT_OPTS +dnl ------------------- dnl Accumulator for the 3rd argument of getopt_long dnl define([<__GETOPT_SHORT_OPTS>],[<_getopt_if_option_set([<nopermute>],+)>]) dnl GROUP(STRING) +dnl ------------- dnl Begin a named group of options dnl -define([<GROUP>],[<dnl -divert(3) +define([<GROUP>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl +WITH_DIVERSION(__DIV_HELPDECL__,[<dnl { NULL, NULL, 0, N_("__getopt_prep([<$1>])") }, -divert(-1)>]) +>])>])>]) # __getopt_quote(args) - convert args to single-quoted string -define([<__getopt_quote>], [<ifelse([<$#>], [<0>], [<>], [<[<$*>]>])>]) -define([<__getopt_dquote>], [<[<$@>]>]) +define([<__getopt_quote>], [<ifelse([<$*>], [<>], [<>], [<[<$*>]>])>]) +define([<__getopt_dquote>], [<ifelse([<$*>], [<>], [<>], [<[<$@>]>])>]) + +# __getopt_ifempty(LIST, IF-TRUE [, IF-FALSE]) +# -------------------------------------------- +# Expands to IF-TRUE if LIST is not empty, otherwise to IF-FALSE. +# +define([<__getopt_ifempty>], [<ifelse([<$1>],[<>],[<$2>],[<$3>])>]) define([<__GATHER_OPTIONS>],[< pushdef([<__GETOPT_KEY>],ifelse([<$2>],,[<OPTION_>]__getopt_upcase(patsubst($1,-,_)),'$2')) ifelse([<$2>],,[< -divert(1) +WITH_DIVERSION(__DIV_OPTKEYS__,[<dnl __GETOPT_KEY, -divert(-1) ->]) +>])>]) define([<__GETOPT_SELECTOR>],ifdef([<__GETOPT_SELECTOR>],__GETOPT_SELECTOR) case __GETOPT_KEY:) ifelse([<$1>],,,[< -divert(2) +WITH_DIVERSION(__DIV_OPTDECL__,[<dnl { "$1", __GETOPT_ARGTYPE, 0, __GETOPT_KEY }, -divert(-1)>]) +>])>]) dnl define([<__GETOPT_SHORT_OPTS>],__getopt_dquote(__GETOPT_SHORT_OPTS[<>]dnl ifelse([<$2>],,,[<$2>]ifelse(__GETOPT_ARGTYPE,[<no_argument>],,__GETOPT_ARGTYPE,[<required_argument>],:,__GETOPT_ARGTYPE,[<optional_argument>],::)))) dnl ifelse([<$1>],,,dnl -[<define([<__GETOPT_LONG_TAG>],ifelse(__GETOPT_LONG_TAG,,[<--$1>],[<__GETOPT_LONG_TAG; --$1>]))>]) +[<define([<__GETOPT_LONG_TAG>], +__getopt_ifempty(__getopt_quote(__GETOPT_LONG_TAG),__getopt_dquote(__getopt_dquote(--$1)),[<__getopt_quote(__getopt_dquote(__GETOPT_LONG_TAG), __getopt_dquote([< --$1>]))>]))>]) ifelse([<$2>],,,dnl -[<define([<__GETOPT_SHORT_TAG>],ifelse(__GETOPT_SHORT_TAG,,[<-$2>],[<__GETOPT_SHORT_TAG; -$2>]))>]) +[<define([<__GETOPT_SHORT_TAG>], +__getopt_ifempty(__getopt_quote(__GETOPT_SHORT_TAG),__getopt_dquote(__getopt_dquote(-$2)),[<__getopt_quote(__getopt_dquote(__GETOPT_SHORT_TAG), __getopt_dquote([< -$2>]))>]))>]) popdef([<__GETOPT_KEY>]) >]) dnl OPTION(long-opt, short-opt, [arg], [descr]) +dnl ------------------------------------------- dnl Introduce a command line option. Arguments: dnl long-opt Long option. dnl short-opt Short option (a single char) @@ -189,7 +226,7 @@ dnl dnl If descr is not given the option will not appear in the --help and dnl --usage outputs. dnl -define([<OPTION>],[< +define([<OPTION>],[<ifelse([<$#>],0,[<[<$0>]>],[< pushdef([<__GETOPT_LONG_TAG>]) pushdef([<__GETOPT_SHORT_TAG>]) pushdef([<__GETOPT_SELECTOR>]) @@ -200,43 +237,47 @@ pushdef([<__GETOPT_ARGTYPE>],[<ifelse([<$3>],,[<no_argument>],dnl patsubst([<$3>],[<\[.*\]>]),,[<optional_argument>],dnl [<required_argument>])>]) __GATHER_OPTIONS($@) ->]) +define([<BEGIN>],[<__GETOPT_API_BEGIN>]) +>])>]) dnl ALIAS(long-opt, short-opt) +dnl -------------------------- dnl Declare aliases for the previous OPTION statement. dnl long-opt Long option. dnl short-opt Short option (a single char) dnl (At least one of long-opt or short-opt must be present) dnl An OPTION statement may be followed by any number of ALIAS statements. dnl -define([<ALIAS>],[< +define([<ALIAS>],[<ifelse([<$#>],0,[<[<$0>]>],[< __GATHER_OPTIONS($1,$2) ->]) +>])>]) dnl BEGIN +dnl ----- dnl Start an action associated with the declared option. Must follow OPTION dnl statement, with optional ALIAS statements in between. dnl -define([<BEGIN>],[< +define([<__GETOPT_API_BEGIN>],[< +undefine([<BEGIN>]) +define([<END>],[<__GETOPT_API_END>]) +define([<LASTOPT>],[<__GETOPT_API_LASTOPT>]) ifelse(__GETOPT_HIDDEN,1,,[< -divert(3) +WITH_DIVERSION(__DIV_HELPDECL__,[<dnl { #ifdef HAVE_GETOPT_LONG - "translit(dnl -ifelse(__GETOPT_SHORT_TAG,,__GETOPT_LONG_TAG,[<__GETOPT_SHORT_TAG[<>]ifelse(__GETOPT_LONG_TAG,,,; __GETOPT_LONG_TAG)>]), - [<;>],[<,>])", + "__getopt_ifempty(__getopt_quote(__GETOPT_SHORT_TAG),__getopt_quote(__GETOPT_LONG_TAG),[<__getopt_quote(__GETOPT_SHORT_TAG)__getopt_ifempty(__getopt_quote(__GETOPT_LONG_TAG),,[<, __getopt_quote(__GETOPT_LONG_TAG)>])>])", #else - "translit(__GETOPT_SHORT_TAG, [<;>],[<,>])", + "__GETOPT_SHORT_TAG", #endif ifelse(__GETOPT_ARGNAME,,[<NULL, 0>], [<ifelse(__GETOPT_ARGTYPE,[<optional_argument>], [<N_(>]"[<patsubst(__GETOPT_ARGNAME,[<\[\(.*\)\]>],[<\1>])>][<"), 1>],[<N_("__GETOPT_ARGNAME"), 0>])>]), N_("__GETOPT_DOCSTRING") }, -divert(-1)>]) +>])>]) popdef([<__GETOPT_ARGTYPE>]) popdef([<__GETOPT_ARGNAME>]) popdef([<__GETOPT_DOCSTRING>]) popdef([<__GETOPT_HIDDEN>]) -divert(4)dnl +divert(__DIV_SWITCH__)dnl popdef([<__GETOPT_LONG_TAG>])dnl popdef([<__GETOPT_SHORT_TAG>])dnl __GETOPT_SELECTOR @@ -244,31 +285,43 @@ popdef([<__GETOPT_SHORT_TAG>])dnl >]) dnl END +dnl --- dnl Finish the associated action dnl -define([<END>],[< +define([<__GETOPT_API_END>],[< break; } divert(-1) +undefine([<END>]) +undefine([<ALIAS>]) +undefine([<LASTOPT>]) popdef([<__GETOPT_SELECTOR>])>]) dnl OPTNODE(name, value) -define([<OPTNODE>],[<do { +dnl -------------------- +define([<OPTNODE>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl +WITH_DIVERSION(__DIV_STATIC__,[< +static struct grecs_node *cmdline_tree; +>]); +do { struct grecs_node *node = grecs_node_from_path($1, $2); if (!cmdline_tree) cmdline_tree = node; else grecs_node_bind(cmdline_tree, node, 0); } while(0) ->]) +>])>]) dnl LASTOPT() -dnl Stop option processing (as if "--" has been encountered -define([<LASTOPT>],[<dnl -define([<__GETOPT_LASTOPT>],[<lastoptlab:>])dnl +dnl --------- +dnl Stop option processing (as if "--" has been encountered) +define([<__GETOPT_API_LASTOPT>],[<dnl +pushdef([<__GETOPT_LASTOPT_LABEL__>],[<lastoptlab: +popdef([<__GETOPT_LASTOPT_LABEL__>])>])dnl goto lastoptlab>]) dnl GETOPT(argc, argv, [long_index], [onerr]) +dnl ----------------------------------------- dnl Emit option parsing code. Arguments: dnl dnl argc Name of the 1st argument to getopt_long. @@ -277,7 +330,8 @@ dnl long_index 5th argument to getopt_long. If not given, dnl NULL will be passed. dnl onerr Action to take if parsing fails. dnl -define([<GETOPT>],[< +define([<GETOPT>],[<ifelse([<$#>],0,[<[<$0>]>],[<dnl +pushdef([<__GETOPT_DEFINED__>],1) { int c; @@ -294,35 +348,40 @@ define([<GETOPT>],[< default: ifelse([<$4>],,,[<$4;>])dnl exit(EX_USAGE); - undivert(4) + undivert(__DIV_SWITCH__) } } -__GETOPT_LASTOPT +__GETOPT_LASTOPT_LABEL__()dnl ifelse([<$3>],,[< if (optind < argc) { fprintf(stderr, "%s: unexpected arguments\n", $2[0]); exit(EX_USAGE); } >],[<$3 = optind;>]) +ifelse(__GETOPT_CMDLINE_TREE_NEEDED__,1,[< if (cmdline_tree) { struct grecs_node *rn = grecs_node_create(grecs_node_root, NULL); rn->down = cmdline_tree; cmdline_tree = rn; } +>])dnl } ->]) +>])>]) define([<_getopt_sc_array>], [<ifelse([<$1>],,,[<[<"$1", >]_getopt_sc_array(shift($@))>])>]) -define([<STDFUNC>],[< -divert(5) +define([<STDFUNC>],[<ifelse([<$#>],0,[<[<$0>]>],[< +WITH_DIVERSION(__DIV_STATIC__,[< ifelse([<$3>],,,[< static char *subcommands[] = { _getopt_sc_array($3) NULL };>]) +#ifndef PACKAGE_URL +# define PACKAGE_URL NULL +#endif static struct grecs_proginfo proginfo = { $2, /* progname */ ifelse([<$3>],,NULL,subcommands), /* subcommands */ @@ -344,33 +403,59 @@ _getopt_if_option_set([<copyright_holder>],dnl PACKAGE_URL, /* url */ NULL /* epilogue */ }; -static struct grecs_node *cmdline_tree; _getopt_if_option_set([<program_version>],dnl [<const char *_getopt_if_option_null(program_version,program_version,[<_getopt_get_option(program_version)>]) = $2 " (" PACKAGE_NAME ") " PACKAGE_VERSION; ->]) -divert(-1) ->]) - -define([<OPTIONS_BEGIN>], - [<divert(-1) - define([<__GETOPT_LASTOPT>]) +>])>])>])>]) + +dnl OPTIONS_BEGIN(PROGNAME, DOCSTR, [ARGDOC], [OPTS...]) +dnl ---------------------------------------------------- +dnl Begins option definition section. Arguments: +dnl PROGNAME - canonical program name, +dnl DOCSTR - usage string to be displayed in --help output. +dnl ARGDOC - docstring for arguments +dnl +dnl Optional arguments (OPTS): +dnl nostdincl - don't emit C include statements for standard include files +dnl nopermute - don't permute arguments, i.e. don't accept intermixed +dnl optional and positional arguments +dnl +dnl gnu - emit code for --help (-h), --version (-V) and --usage +dnl options. +dnl Options bellow modify the effect of the 'gnu' option: +dnl +dnl nousage - disable support for the --usage option +dnl noversion - disable support for the --version option +dnl +dnl copyright_year=Y +dnl Year, or range, or list of years to display in +dnl the copyright statement. Default is 2012 (why?) +dnl copyright_holder=NAME +dnl Copyright holder name. Default is 'Free Software Foundation, +dnl inc.' +dnl program_version=V +dnl Version string. Defaults to PACKAGE_VERSION autoconf define. +dnl +define([<OPTIONS_BEGIN>],[<ifelse([<$#>],0,[<[<$0>]>], + [<divert(-1) _getopt_set_options(shift(shift(shift($@)))) + pushdef([<__GETOPT_EXPECT_ARGS__>],ifelse(__getopt_quote($3),,0,1)) _getopt_if_option_set([<gnu>], [<STDFUNC([<$1 " (" PACKAGE_NAME ") " PACKAGE_VERSION>], - [<$1>], [<>], [<$2>], [<$3>])>]) ->]) + [<$1>], [<>], [<$2>], [<$3>])>])>])>]) + -define([<OPTIONS_COMMAND_BEGIN>], +define([<OPTIONS_COMMAND_BEGIN>],[<ifelse([<$#>],0,[<[<$0>]>], [<divert(-1) - define([<__GETOPT_LASTOPT>]) _getopt_set_options(shift(shift(shift(shift($@))))) + pushdef([<__GETOPT_EXPECT_ARGS__>],ifelse(__getopt_quote($3),,0,1)) _getopt_if_option_set([<gnu>], [<STDFUNC([<$1 " (" PACKAGE_NAME ") " PACKAGE_VERSION>], [<$1>], [<$2>], [<$3>], [<$4>])>]) ->]) +>])>]) define([<OPTIONS_END>],[< +pushdef([<__OPTIONS_END_DEFINED__>],1) _getopt_if_option_set([<gnu>],[< GROUP([<Other options>]) OPTION([<help>],h,,[<Give this help list>]) @@ -387,40 +472,69 @@ _getopt_if_option_set([<nousage>],,[< _getopt_if_option_set([<noversion>],,[< OPTION([<version>],V,,[<Print program version>]) BEGIN - /* Give version */ + /* Give version */ grecs_print_version(&proginfo, stdout); exit(0); END>])>]) -divert -_getopt_if_option_set([<nostdincl>],,[< -#ifdef HAVE_CONFIG_H +divert(0)dnl +_getopt_if_option_set([<nostdincl>],, +[<#ifdef HAVE_CONFIG_H # include <config.h> #endif #ifdef HAVE_GETOPT_H # include <getopt.h> #endif #include <unistd.h> ->]) +#include <stdlib.h> +>])dnl #include <grecs.h> #include <grecs/opt.h> +#ifndef [<EX_USAGE>] +# define [<EX_USAGE>] 64 +#endif /* Option codes */ enum { _OPTION_INIT=255, - undivert(1) +undivert(__DIV_OPTKEYS__)dnl MAX_OPTION }; #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { - undivert(2) +undivert(__DIV_OPTDECL__)dnl {0, 0, 0, 0} }; #endif +_getopt_if_option_set([<gnu>],[< static struct grecs_opthelp opthelp[] = { - undivert(3) +undivert(__DIV_HELPDECL__)dnl }; -undivert(5) +>],[<WITH_DIVERSION(-1,[<undivert(__DIV_HELPDECL__)>])>])dnl +undivert(__DIV_STATIC__) >]) +m4wrap([<ifelse(__OPTIONS_END_DEFINED__,1,,[<OPTIONS_END()>])dnl +ifelse(__GETOPT_DEFINED__,1,,[<divert(0)dnl +ifelse(__GETOPT_EXPECT_ARGS__,1,[< +int +parse_options(int argc, char **argv, int *idx) +{ + GETOPT(argc, argv, *idx) + return 0; +} +>],[< +int +parse_options(int argc, char **argv) +{ + GETOPT(argc, argv) + return 0; +} +>]) +divert(-1) +popdef([<__GETOPT_DEFINED__>]) +popdef([<__GETOPT_EXPECT_ARGS__>]) +popdef([<__OPTIONS_END_DEFINED__>]) +popdef([<__GETOPT_LASTOPT_LABEL__>])>])>]) + divert(0)dnl /* -*- buffer-read-only: t -*- vi: set ro: THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. |