Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* avp 2015
- av_getopt(), av_opt_help(), ... argvopt(): argv[] parser. TEMPLATE version
- Author
- ------
- Vasily Anishchenko (avp210159@mail.ru)
- Code is hereby licensed under the MIT Public License:
- Copyright (C) 2015 Vasily Anishchenko
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
- Данная лицензия разрешает, безвозмездно, лицам, получившим копию
- данного программного обеспечения и сопутствующей документации
- (в дальнейшем именуемыми "Программное Обеспечение"), использовать
- Программное Обеспечение без ограничений, включая неограниченное право
- на использование, копирование, изменение, объединение, публикацию,
- распространение, сублицензирование и/или продажу копий Программного
- Обеспечения, также как и лицам, которым предоставляется данное
- Программное Обеспечение, при соблюдении следующих условий:
- Вышеупомянутый копирайт и данные условия должны быть включены
- во все копии или значимые части данного Программного Обеспечения.
- ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ»,
- БЕЗ ЛЮБОГО ВИДА ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ,
- ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ,
- СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И НЕНАРУШЕНИЯ ПРАВ.
- НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ
- ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО
- ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ
- ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ
- ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
- */
- /*
- Based on the known functions: getopt_long() and argp_parse()
- Small example:
- avp@avp-ubu1:examples$ gcc a-minitar.c -I.. && ./a.out --help
- Usage: (1) a.out -c,--create -f,--file=ARCHIVE [ -z -v,--verbose
- -?,--help --usage -V,--version --Help-grp ] FILE [FILE ...]
- create archive
- or : (2) a.out -t,--list [ -f,--file=ARCHIVE -z -v,--verbose
- --wildcards[=TYPE] -?,--help --usage -V,--version --Help-grp ]
- [FILE ...]
- list archive
- or : (3) a.out -x,--extract [ -f,--file=ARCHIVE -z -v,--verbose
- --wildcards[=TYPE] -?,--help --usage -V,--version --Help-grp ]
- [FILE ...]
- extract files from archive
- command options (MUST use only one):
- -c, --create create a new archive
- -t, --list list the contents of an archive
- -x, --extract extract files from an archive
- other common options:
- -f, --file ARCHIVE use archive file or device ARCHIVE
- -z try compress archive
- -v, --verbose verbosely list files processed
- list and extract specific options:
- --wildcards[=TYPE] use wildcards (default "Shell")
- -?, --help help text
- --usage short reference
- -V, --version programm version
- --Help-grp help text (with option <groups-mask>)
- Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options.
- Just little example of argvopt groups
- avp@avp-ubu1:examples$ cat a-minitar.c
- #include <argvopt.h>
- struct user_opts {
- char *archive;
- char *wc_type;
- int create, list, extract, verbose, compress;
- };
- static int
- check_options (int key, char *arg, struct av_state *st)
- {
- if (key != AV_KEY_FINI || st->tot_err)
- return key;
- struct user_opts *a = (typeof(a))st->glue;
- if (!(a->create | a->list | a->extract))
- st->msg = strdup("You must specify one of the '-ctx' options");
- else if (a->create) {
- if (!a->archive)
- st->msg = strdup("-f ARCHIVE required for --create option");
- else if (!st->n_args)
- st->msg = strdup("Cowardly refusing to create an empty archive");
- }
- return st->msg ? AV_ANYERR : key;
- }
- #define DEFWC "Shell"
- static int
- wc_proc_opt (int key, char *arg, struct av_state *st, AV_DCLOPT_T *t)
- {
- if (key == 1) {
- if (!arg)
- *(t->optarg_ptr) = (char *)DEFWC;
- else if (!*arg)
- *(t->optarg_ptr) = 0;
- }
- return key;
- }
- int
- main (int ac, char *av[])
- {
- struct user_opts a = {0};
- AV_DCLOPT_T dcl[] = {
- {0, 0, "command options (MUST use only one):"},
- {"create", 'c', "create a new archive", AV_MGRP1, &a.create},
- {"list", 't', "list the contents of an archive", AV_MGRP2, &a.list},
- {"extract", 'x', "extract files from an archive", AV_MGRP3, &a.extract},
- {0, 0, "other common options:"},
- {"file", 'f', "use archive file or device ARCHIVE\vARCHIVE",
- AV_HASARG | AV_MND(1), 0, &a.archive},
- {0, 'z', "try compress archive", 0, &a.compress},
- {"verbose", 'v', "verbosely list files processed", 0, &a.verbose},
- {0, 0, "list and extract specific options:"},
- {"wildcards", 1, "use wildcards (default "_STR(DEFWC)")\vTYPE",
- AV_OPTARG | AV_GRP2 | AV_GRP3, 0, &a.wc_type, wc_proc_opt},
- {0, 0, " "},
- {AV_HUV()},
- {AV_HELP_GRP("")},
- {0}
- };
- av_program_doc = "\vJust little example of argvopt groups";
- av_args_doc = "\01 FILE [FILE ...]\n\tcreate archive"
- "\02 [FILE ...]\n\tlist archive"
- "\03 [FILE ...]\n\textract files from archive";
- av_program_version = "minitar argvopt example 1.1";
- av_wrap_pos = 58;
- struct av_state *ap = argvopt(ac, av, dcl, 0,
- AV_ERRENDEXIT | AV_QUIET_EXIT,
- check_options, &a);
- printf("Your choice: %s\n"
- "archive: %s\n"
- "verbose level: %d\n"
- "with%s compression\n",
- a.create ? "Create" : a.list ? "View" : "Extract",
- a.archive ? : "< stdin",
- a.verbose,
- a.compress ? "" : "out");
- if (a.wc_type) {
- printf("use");
- if (a.wc_type[0])
- printf(" '%s'", a.wc_type);
- puts(" wildcards in archive FILE names");
- }
- if (ap->n_args) {
- printf("action performes for files:");
- int i;
- for (i = 0; i < ap->n_args || !puts(""); i++)
- printf(" %s", ap->args[i]);
- }
- return puts("End") == EOF;
- }
- avp@avp-ubu1:examples$
- */
- /*
- TODO
- +- check zopt
- callbacks break loop -- args tail ?
- fixed/variable chunks arrays
- +- more user #ifdef's ?
- +- test suit
- doc
- DONE
- ++ move AV_LONGOPT_AMBIGUOUS AV_NOCOMPATOPT messages to av_errormsg
- ++ move compat check code to _av_getopt
- ++ move user global callback to av_getopt
- ++ change commom callback args to: key, arg, state (like in argp_parse())
- ++ move store args to av_getopt() before callbacks
- ++ no duplicates in .opts[], .eropts[], .args[] and order by index in argv[]
- ++ write check av[] type func() for callbacks
- ++ collect messages, do them available in user loop
- in LONGOPT_ONLY mode
- ++ ambigous -- stop reparsing av[i] as short opts, goto next
- ++ first unknown short opt -- stop parsing av[i], report - unrecogn for rest
- */
- #ifndef _ARGVOPT_H
- #define _ARGVOPT_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdint.h>
- #include <limits.h>
- #include <stdarg.h>
- #ifdef unix
- #include <sysexits.h>
- #else
- #define EX_USAGE 1
- #include <windows.h>
- #endif
- #ifndef AV_DCLOPT_T
- #define AV_DCLOPT_T struct av_dclopt
- #define _AV_NEED_DCL
- struct av_dclopt; // forward declaration
- #endif
- struct av_opt {
- int optind,
- optchr,
- optlen,
- dclindex,
- argind,
- argchr;
- AV_DCLOPT_T *dcl;
- char *arg;
- };
- struct av_opterr {
- char *errmsg;
- int errcode;
- struct av_opt opt;
- };
- struct av_state;
- typedef int (*ucallback_t)(int key, char *arg, struct av_state *state);
- struct av_state {
- // input fields
- int argc; // .argv[] length
- char **argv; // arguments vector
- int flags; // av_getopt() behavior
- // flags AV_STOP_NONOPT_ARG | getenv("POSIXLY_CORRECT") as +OPTS in getopt()
- #define AV_STOP_NONOPT_ARG 0x1 // return AV_END and copy remaining arguments
- #define AV_SILENT 0x2 // don't print error messages
- #define AV_CHECK_DCL 0x4 // for debug (if errors exit in _av_initcheck())
- #define AV_LONGOPT_ONLY 0x8 // --opt and -opt are the same (man getopt_long)
- #define AV_DIGIT_OPTION 0x10 // -1, -2.73e2 and similar are options too
- #define AV_PARSE_ARGV0 0x20 // argv[0] is argument too
- #define AV_ERREXIT 0x40 // argvopt() exit on first error
- #define AV_ERRBREAK 0x80 // argvopt() break parse on first error
- #define AV_ERRENDEXIT 0x100 // argvopt() exit after parsing if errors
- #define AV_QUIET_EXIT 0x200 // don't print usage messages on err exit
- AV_DCLOPT_T *dcl; // current dcl[]
- int dcl_itemsize; // for external dcl[] functions purpose
- void *glue; // dcl[] user functions link area
- ucallback_t u_callback; // user common callback
- FILE *out; // error messages stream (stderr if 0)
- // result fields
- char **args; // not option arguments list (dynamic, NULL - init indicated)
- int *iargs; // their indices
- struct av_opt *opts; // processed options ordered by optind,optchr
- struct av_opterr *eropts; // error options ordered by optind,optchr
- int n_args, // current .args[] size
- arg_tail, // index in .args[] of not parsed .argv[] arguments
- n_opts, // number of processed options in .opts[]
- n_err, // number of error options in .eropts[]
- tot_err, // total errors counter with init, ... uvfun(AV_KEY_INI,...) and other
- groups; // bitmask of compatible options groups in .opts[]
- // current state of parsing
- char *optarg, // parsed argument or 0
- *optsrc; // option field in .argv[i] or 0
- int zopt, // same as opt = av_getopt() result, but ... (see source code)
- /*
- we want that zopt is dcl[].key or 0 if returns ARG or AV_END (-1) if END
- set AV_KEY_NONE at init
- */
- optind, // .argv[optind] is next for parsing
- optchr, // offset of next char in argv[optind] (clear every step to next)
- optlen, // long option length (long option indicator)
- optopt, // 0 or short option value (may be unknown) or not changed
- dclindex, // index in dcl_option[] if option found or -1
- cur_argind, // index in argv[] of optarg or -1
- cur_optind, // index in argv[] of option or -1
- cur_optchr; // option character offset in .argv[.cur_optind] or -1
- char *msg; // all messages (errors) (separated by '\n')
- int do_msg; // callback control: 0 -- if rc < 0 av_getopt don't do message
- };
- // opt = av_getopt() returns av_dclopt.key or codes:
- #define AV_ARG 0
- #define AV_END -1
- #define _AV_DASHDASH -100
- #define _AV_OPTION -99
- #define AV_LONGOPT_REQ_ARG -2 // option '--in' requires an argument
- #define AV_LONGOPT_NOTALLOW_ARG -3 // option '--help' doesn't allow an argument
- #define AV_LONGOPT_AMBIGUOUS -4 // option '--ar' is ambiguous; possibilities: '--arg' '--arg2' ...
- #define AV_NO_LONGOPT -5 // unrecognized option '--in'
- #define AV_NO_OPTION -6 // invalid option -- 'i'
- #define AV_OPTION_REQ_ARG -7 // option requires an argument -- 'i'
- #define AV_NOCOMPATOPT -8 // option not compatible with other groups
- #define AV_NOMEM -12
- #define AV_USAGE_ERROR -13 // fatal, nil state/dcl data
- #define AV_ARGV_ERROR -14 // fatal, bad ac/av[]
- #define AV_ANYERR -15 // some error callback return
- #define AV_BREAK -16 // not error callback break processing loop
- #define AV_DEFVAR -20
- #define AV_DATAERR -21
- #ifndef AV_NOUSEVAR
- // user function: may returns AV_END or AV_BREAK for stop parsing
- typedef int (*optfunc_t)(int opt, char *arg,
- struct av_state *state, AV_DCLOPT_T *thisdcl);
- #endif
- #define AV_KEY_SPEC 0x70000000 // first not user key
- #define AV_KEY_NONE 0x70000001
- #ifndef AV_USAGE_KEY
- #define AV_USAGE_KEY (AV_KEY_SPEC - 1) // used for --usage in AV_USAGE/AV_HUV
- #endif
- #ifndef AV_HELPG_KEY
- #define AV_HELPG_KEY (AV_KEY_SPEC - 2) // used for --Help-grp in AV_USAGE/AV_HUV
- #endif
- #ifndef AV_HELP_KEY
- #define AV_HELP_KEY ('?') // used for --help in AV_USAGE/AV_HUV
- #endif
- #ifndef AV_VERSION_KEY
- #define AV_VERSION_KEY ('V')
- #endif
- #define AV_KEY_INIT 0x7fffffff
- #define AV_KEY_FINI 0x7ffffffe
- #ifdef _AV_NEED_DCL
- // Minimal declaration. Used in parse/help argv[] functions
- // Should be first and continuous fields in any other declaration struct
- struct av_dclopt {
- const char *name; // long option
- int key; // short option if isgraph()
- // this field returns by av_getopt(), should be > 0
- const char *descr; // description text for help in format: TEXT\vARGNAME
- int def_arg; // HASARG + Groups + other up levels description bits
- #ifndef AV_NOUSEVAR // set program variables to parsed options value
- int *opt_counter; // incr
- char **optarg_ptr; // optarg value
- optfunc_t uvfun; // function called after set variable
- const void *arg1, // 2 user arguments to function
- *arg2;
- char *processed; // ptr to last successfully processed option in argv[]
- #endif
- };
- #undef _AV_NEED_DCL
- #endif // _AV_NEED_DCL
- // struct dcl_option .def_arg HASARG values
- #define AV_NOARG 0 // equal no_argument from getopt.h
- #define AV_HASARG 1 // required_argument
- #define AV_OPTARG 2 // optional_argument
- #define AV_HASARG_MASK 0x3
- /*
- Option can belongs to one or more (now maximum 5) groups (numbers from 1 to 5)
- Options that has no one common group are uncompatible.
- Zero group option (option that is not in any group) is compatible with any
- other options.
- _av_getopt() checks options compatibility
- av_help()/av_usage() groups compatible options together in Usage: lines
- */
- #define _MAKEMASK(len,ofs) ( ((1 << (len)) - 1) << (ofs) )
- #define _GETMASKV(v,mask,ofs) (((v) & (mask)) >> (ofs))
- #define AV_GRP_OFS 3
- #define AV_GRP_LEN 5
- #define AV_GROUP_MASK _MAKEMASK(AV_GRP_LEN, AV_GRP_OFS)
- // macros for init .def_arg (may be ored)
- #define AV_GRP(n) (1 << (AV_GRP_OFS + (((n) < AV_GRP_LEN) ? n : AV_GRP_LEN) - 1))
- #define AV_GRP1 AV_GRP(1)
- #define AV_GRP2 AV_GRP(2)
- #define AV_GRP3 AV_GRP(3)
- #define AV_GRP4 AV_GRP(4)
- #define AV_GRP5 AV_GRP(5)
- // macros for get groups value
- #define AV_VGROUPS(v) _GETMASKV((v), AV_GROUP_MASK, AV_GRP_OFS)
- #define AV_GROUPS(p) AV_VGROUPS((p)->def_arg)
- // options mandatoring (now only for print) 5 bit (by groups -- allways==11111)
- #define AV_MND_OFS (AV_GRP_LEN + AV_GRP_OFS)
- #define AV_MND_MASK _MAKEMASK(AV_GRP_LEN, AV_MND_OFS)
- #define AV_VMANDAT(v) _GETMASKV((v), AV_MND_MASK, AV_MND_OFS)
- #define AV_MANDAT(p) AV_VMANDAT((p)->def_arg)
- #define AV_MND(n) (1 << (AV_MND_OFS + (((n) < AV_GRP_LEN) ? n : AV_GRP_LEN) - 1))
- #define AV_GMND(n) (AV_MND(n) | AV_GRP(n))
- #define AV_MNDTRY (((1 << AV_GRP_LEN) - 1) << AV_MND_OFS)
- #define AV_MGRP1 AV_GMND(1)
- #define AV_MGRP2 AV_GMND(2)
- #define AV_MGRP3 AV_GMND(3)
- #define AV_MGRP4 AV_GMND(4)
- #define AV_MGRP5 AV_GMND(5)
- // typed value options
- #ifndef AV_NOUSEVAR
- #define AV_TYPE_LEN 10
- #define AV_TYPE_OFS (AV_GRP_LEN + AV_MND_OFS)
- #define AV_TYPE_MASK _MAKEMASK(AV_TYPE_LEN, AV_TYPE_OFS)
- // .optarg_ptr types
- #define _AV_STR_T 0
- #define _AV_INT8_T (0x1 << AV_TYPE_OFS)
- #define _AV_UINT8_T (0x2 << AV_TYPE_OFS)
- #define _AV_INT16_T (0x4 << AV_TYPE_OFS)
- #define _AV_UINT16_T (0x8 << AV_TYPE_OFS)
- #define _AV_INT32_T (0x10 << AV_TYPE_OFS)
- #define _AV_UINT32_T (0x20 << AV_TYPE_OFS)
- #define _AV_INT64_T (0x40 << AV_TYPE_OFS)
- #define _AV_UINT64_T (0x80 << AV_TYPE_OFS)
- #define _AV_FLOAT_T (0x100 << AV_TYPE_OFS)
- #define _AV_DOUBLE_T (0x200 << AV_TYPE_OFS)
- #define AV_STR AV_HASARG
- #define AV_INT8 (_AV_INT8_T | AV_HASARG)
- #define AV_UINT8 (_AV_UINT8_T | AV_HASARG)
- #define AV_INT16 (_AV_INT16_T | AV_HASARG)
- #define AV_UINT16 (_AV_UINT16_T | AV_HASARG)
- #define AV_INT32 (_AV_INT32_T | AV_HASARG)
- #define AV_UINT32 (_AV_UINT32_T | AV_HASARG)
- #define AV_INT64 (_AV_INT64_T | AV_HASARG)
- #define AV_UINT64 (_AV_UINT64_T | AV_HASARG)
- #define AV_FLOAT (_AV_FLOAT_T | AV_HASARG)
- #define AV_DOUBLE (_AV_DOUBLE_T | AV_HASARG)
- // array options
- #define AV_ISARRAY (1 << (AV_TYPE_LEN + AV_TYPE_OFS))
- #define AV_ARRAY (AV_HASARG | AV_ISARRAY)
- // array chunk (under costruction yet)
- #define AV_ARRAYS(n) (AV_ARRAY | ((n) << (AV_TYPE_LEN + AV_TYPE_OFS + 1)))
- #define AV_GETARRAYSZ(v) ((v) >> (AV_TYPE_LEN + AV_TYPE_OFS + 1))
- #endif // AV_NOUSEVAR
- #define ISEMPTY_DCL(d) ({ typeof (d) _p = (d); \
- _p ? (_p->name == 0 && _p->key == 0 && _p->descr == 0) : 1; })
- #define __STR(t) #t
- #define _STR(t) __STR(t)
- #define NAME_DCLOPT_TYPE _STR(AV_DCLOPT_T)
- #ifdef unix
- extern char *__progname;
- #else
- static const char *__progname = "???.exe";
- #endif
- #ifndef AV_NOCODE
- // Smth like getopt_long() see: man 3 getopt
- // Returns av_dclopt.key or 0 (arg) or -1 (finish) or ERRCODE < -1
- // set user variables, call callbacks, make messages and so on
- static int av_getopt (struct av_state *st);
- // most internal argv parser, only returns code
- static int _av_getopt (struct av_state *st);
- // Smth like GNU argp_parse() see: http://www.gnu.org/software/libc/manual/html_node/Argp.html
- // Returns malloced struct av_state
- static struct av_state *
- argvopt (int ac, char *av[], AV_DCLOPT_T *dcl, FILE *out,
- int flags, ucallback_t uf, void *glue);
- #define ARGP(ac, av, dcl, flags) argvopt(ac, av, dcl, 0, flags, 0, 0)
- static void *av_state_free (struct av_state *st, int free_st);
- static int av_match_names (char *avitem, AV_DCLOPT_T dcl[], int **res);
- static char *av_errormsg (struct av_state *st, int code);
- static void
- av_opt_usage (AV_DCLOPT_T dcl[], const char *hmsg, const char *emsg, FILE *out);
- static int
- av_dcl_usage (int key, char *a, struct av_state *st, AV_DCLOPT_T *td);
- #ifndef AV_USAGE
- #define AV_USAGE(rc, ...) "usage", AV_USAGE_KEY, "short reference", 0, 0, (char **)rc, av_dcl_usage, ##__VA_ARGS__
- #endif
- // full help (with usage()) without groups
- static void
- av_opt_help (AV_DCLOPT_T dcl[], const char *hmsg, const char *emsg, FILE *out);
- static int
- av_dcl_help (int key, char *a, struct av_state *st, AV_DCLOPT_T *td);
- #ifndef AV_HELP
- #define AV_HELP(rc, ...) \
- "help",AV_HELP_KEY,"help text",0,0,(char **)rc,av_dcl_help,##__VA_ARGS__
- #endif
- // full help (with usage()) with groups
- static int
- av_dcl_help1 (int key, char *a, struct av_state *st, AV_DCLOPT_T *td);
- #ifndef AV_HELP_GRP
- #define AV_HELP_GRP(rc, ...) \
- "Help-grp",AV_HELPG_KEY,"help text (with option <groups-mask>)",0,0,(char **)rc,av_dcl_help1,##__VA_ARGS__
- #endif
- // help without usage() and options groups info (only opt description list)
- static void
- av_opt_help2 (AV_DCLOPT_T *dcl, const char *beg_end_msg, const char *args_msg, FILE *out, int prigroups);
- static int
- av_dcl_help2 (int key, char *a, struct av_state *st, AV_DCLOPT_T *td);
- // print version
- static int
- av_dcl_version (int key, char *a, struct av_state *st, AV_DCLOPT_T *td);
- #ifndef AV_VERSION
- #define AV_VERSION(rc) "version", AV_VERSION_KEY, "programm version", 0, 0, (char **)rc, av_dcl_version
- #endif
- // dcl print help, usage & versin together
- #ifndef AV_HUV
- #define AV_HUV(...) AV_HELP("",##__VA_ARGS__)},{AV_USAGE("",##__VA_ARGS__)},{AV_VERSION("")
- #endif
- #ifndef AV_HUV_NOEX
- #define AV_HUV_NOEX(...) AV_HELP(0,##__VA_ARGS__)},{AV_USAGE(0,##__VA_ARGS__)},{AV_VERSION(0)
- #endif
- // for debug
- static void
- av_print_dcl (AV_DCLOPT_T *dp, FILE *out);
- static int
- av_check_dcl (AV_DCLOPT_T *dp, FILE *out); // for debug, exit if errors
- static AV_DCLOPT_T *av_find_dcl (int key, struct av_state *st);
- static int av_addyna (char **pa, int *pn, const char *arg, int itemsize);
- // well, I think that isgraph() and other MUST be improved
- static inline int Isgraph (int c) {
- return c > 0 && c < 256 ? isgraph(c) : 0;
- }
- #define DYNALIM 1024
- // add new item to dynamic array, returns array size or 0 if no memory
- static int
- av_addyna (char **pa, int *pn, const char *arg, int itemsize)
- {
- // array capacity as f(size)
- // 0 : 2+, 1 : 4+, 2 : 4, 3 : 8+, 4 : 8, 5 : 8, 6 : 8, 7 : 16+ ...
- int size, old, n = *pn;
- if (n < 0)
- n = 0;
- char *t = *pa;
- if (n < DYNALIM) {
- size = 1 << (32 - __builtin_clz(n + 1));
- old = n ? 1 << (32 - __builtin_clz(n)) : 1;
- } else {
- size = ((n + 1) & ~(DYNALIM - 1)) + DYNALIM;
- old = (n & ~(DYNALIM - 1)) + DYNALIM;
- }
- if (old != size )
- if (!(*pa = (char *)realloc(*pa, size * itemsize))) {
- *pa = t;
- return 0;
- }
- memcpy(*pa + n++ * itemsize, arg, itemsize);
- memset(*pa + n * itemsize, 0, itemsize);
- return *pn = n;
- }
- #undef DYNALIM
- #ifndef unix
- static void _av_setwinprogname ()
- {
- if (__progname[0] == '?') {
- char pname[10240];
- GetModuleFileName(0, pname, sizeof(pname) - 1);
- char *p = strrchr(pname, '\\');
- __progname = strdup(p ? p + 1 : pname);
- }
- }
- #endif
- #ifndef _GNU_SOURCE
- static int
- asprintf (char **ps, const char *fmt, ...)
- {
- // puts("my asprintf");
- va_list ap;
- va_start(ap, fmt);
- int rc = vsnprintf(*ps, 0, fmt, ap);
- va_end(ap);
- if (rc >= 0) {
- if ((*ps = (char *)malloc(rc + 2))) {
- va_start(ap, fmt);
- rc = vsnprintf(*ps, rc + 1, fmt, ap);
- va_end(ap);
- } else
- rc = -1;
- }
- return rc;
- }
- #endif
- static int
- _av_addmsg (char **p, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- int l = vsnprintf(*p, 0, fmt, ap);
- va_end(ap);
- if (l > 0) {
- int ll = *p ? strlen(*p) : 0, pnl = ll;
- if (pnl)
- ll++;
- if ((*p = (char *)realloc(*p, l + ll + 1))) {
- if (pnl)
- (*p)[pnl] = '\n';
- va_start(ap, fmt);
- vsnprintf((*p) + ll, l + 1, fmt, ap);
- va_end(ap);
- } else
- l = -1;
- }
- return l;
- }
- // Called if found ARGUMENT or END, Returns code
- static inline int _av_clropt (int code, struct av_state *st) {
- st->optchr = st->optlen = 0;
- return st->zopt = code;
- }
- // Modify av_state for processing next argv[]
- static inline int _av_nextargv (int code, struct av_state *st) {
- st->optind++; st->optchr = 0;
- return code;
- }
- // Add arg to av_state.args[]
- static int _av_add_arg (struct av_state *st, int i) {
- int rc = 1;
- if (i >= 0 && i < st->argc) {
- int j, n = st->n_args, l;
- for (j = n - 1; j > 0 && st->iargs[j] > i; j--);
- if (!(n && st->iargs[j] == i)) {
- if (j < 0 || st->iargs[j] < i)
- j++;
- rc = av_addyna((char **)&st->iargs, &n, (char *)&i, sizeof(int)) &&
- av_addyna((char **)&st->args, &st->n_args,
- (char *)&st->argv[i], sizeof(char *));
- if (rc && (l = (n - 1 - j))) {
- memmove((char *)(st->iargs + j + 1), (char *)(st->iargs + j),
- l * sizeof(int));
- memmove((char *)(st->args + j + 1), (char *)(st->args + j),
- l * sizeof(char *));
- st->iargs[j] = i;
- }
- }
- st->args[j] = st->argv[i];
- }
- return rc;
- }
- static inline int
- _av_cmp_optpos (void *o1, void *o2)
- {
- struct av_opt *a1 = (typeof(a1))o1, *a2 = (typeof(a2))o2;
- return a1->optind < a2->optind ? -1 :
- a1->optind > a2->optind ? 1 :
- a1->optchr < a2->optchr ? -1 : a1->optchr != a2->optchr;
- }
- static inline int
- _av_cmp_opterrpos (void *o1, void *o2)
- {
- struct av_opterr *a1 = (typeof(a1))o1, *a2 = (typeof(a2))o2;
- return _av_cmp_optpos(&a1->opt, &a2->opt);
- }
- // Add av_opt to av_state.opts[] (or av_opterr to av_state.eropts[])
- static int
- _av_store_opts (int *n_items, void **optarr_addr,
- void *opt_item, int item_size, int (*fcmp)(void *o1, void *o2))
- {
- int rc = 1, j, l;
- char **a = (char **)optarr_addr;
- for (j = *n_items - 1; j > 0 && fcmp(*a + j * item_size, opt_item) > 0; j--);
- if (!(*n_items && fcmp(*a + j * item_size, opt_item) == 0)) {
- if (j < 0 || fcmp(*a + j * item_size, opt_item) < 0)
- j++;
- rc = av_addyna(a, n_items, (char *)opt_item, item_size);
- if (rc && (l = (*n_items - 1 - j) * item_size))
- memmove(*a + (j + 1) * item_size, *a + j * item_size, l);
- }
- memcpy(*a + j * item_size, (char *)opt_item, item_size);
- return rc;
- }
- // Called if there are no more options, args only. Returns END.
- static int
- _av_copytail (struct av_state *st, int i)
- {
- char **av = st->argv;
- if (st->arg_tail == -1 && i < st->argc && av[i]) {
- st->arg_tail = st->n_args;
- for (; i < st->argc && av[i]; i++)
- if (!_av_add_arg(st, i))
- return AV_NOMEM;
- }
- return _av_clropt(AV_END, st);
- }
- // Search argv[i] type
- static int
- _av_argtype (struct av_state *st, int i)
- {
- if (i >= st->argc || !st->argv[i])
- return AV_END;
- if (strcmp(st->argv[i], "--") == 0)
- return _AV_DASHDASH;
- if (st->argv[i][0] != '-' || st->argv[i][1] == 0 // "-"
- || strncmp(st->argv[i], "---", 3) == 0
- // arguments like -1 or -2.73e+2 may be not option too
- || (isdigit(st->argv[i][1]) && !(st->flags & AV_DIGIT_OPTION)))
- return AV_ARG;
- return _AV_OPTION;
- }
- // Search current (using av_state) short option in dcl[]
- static int
- _av_findkey (AV_DCLOPT_T *dcl, struct av_state *st)
- {
- st->dclindex = -1;
- int i, c;
- if (st->optsrc && Isgraph(c = st->optsrc[st->optchr]))
- for (i = 0; !ISEMPTY_DCL(dcl + i); i++)
- if ((dcl + i)->key == c)
- return (st->dclindex = i), c;
- return 0;
- }
- // Search dcl[] by short key
- static AV_DCLOPT_T *
- av_find_dcl (int key, struct av_state *st)
- {
- AV_DCLOPT_T *dcl = st->dcl;
- int i;
- for (; !ISEMPTY_DCL(dcl); dcl++)
- if (dcl->key == key)
- return dcl;
- return 0;
- }
- #ifndef AV_NOUSEVAR
- // Make dcl option name in buf[] for error message. Returns this name
- static char *
- _av_dclname (AV_DCLOPT_T *d, char buf[])
- {
- if (d->name)
- sprintf(buf, "--%s", d->name);
- else
- sprintf(buf, "-%c", d->key);
- return buf;
- }
- // Make dcl array error message for _av_initcheck() & _av_put_data()
- static int
- _av_check_arraydef (AV_DCLOPT_T *d, struct av_state *st)
- {
- char msg[100];
- int l = 0;
- if (d->def_arg & AV_ISARRAY) {
- if ((d->def_arg & AV_HASARG_MASK) != AV_HASARG)
- l = sprintf(msg, "array need only AV_HASARG");
- if (!d->opt_counter)
- l += sprintf(msg + l, "%s%s", l ? ", " : "", "array need counter");
- if (!d->optarg_ptr)
- l += sprintf(msg + l, "%s%s", l ? ", " : "", "array need optarg_ptr");
- if (l) {
- char buf[d->name ? strlen(d->name) + 3 : 3];
- st->do_msg = 0;
- return (_av_addmsg(&st->msg, "option %s: dcl error - %s",
- _av_dclname(d, buf), msg) < 0) ?
- AV_NOMEM : AV_DEFVAR;
- }
- }
- return 0;
- }
- // Sizeof AV_type
- static int
- _av_get_tsize (int type)
- {
- static struct {
- int type, size;
- } ts[] = {{_AV_STR_T, sizeof(char *)},
- {_AV_INT8_T, sizeof(int8_t)},
- {_AV_UINT8_T, sizeof(uint8_t)},
- {_AV_INT16_T, sizeof(int16_t)},
- {_AV_UINT16_T, sizeof(uint16_t)},
- {_AV_INT32_T, sizeof(int32_t)},
- {_AV_UINT32_T, sizeof(uint32_t)},
- {_AV_INT64_T, sizeof(int64_t)},
- {_AV_UINT64_T, sizeof(uint64_t)},
- {_AV_FLOAT_T, sizeof(float)},
- {_AV_DOUBLE_T, sizeof(double)},
- {0,0}};
- int i;
- for (i = 0; ts[i].size; i++)
- if (ts[i].type == type)
- return ts[i].size;
- return 0;
- }
- // Make dcl variable type error message for _av_put_data() & _av_initcheck()
- static int
- _av_type_error (AV_DCLOPT_T *d , struct av_state *st)
- {
- char buf[d->name ? strlen(d->name) + 3 : 3];
- st->do_msg = 0;
- return _av_addmsg(&st->msg, "option %s: dcl error - unknown type",
- _av_dclname(d, buf)) < 0 ?
- AV_NOMEM: AV_DEFVAR;
- }
- // Make errno error message for _av_put_data()
- static int
- _av_data_error (AV_DCLOPT_T *d, const char *arg, int old, struct av_state *st)
- {
- char buf[d->name ? strlen(d->name) + 3 : 3];
- const char *msg = errno ? strerror(errno) : "invalid character";
- st->do_msg = 0;
- return _av_addmsg(&st->msg, "option %s <%s>: data format or value error - %s",
- _av_dclname(d, buf), arg, msg) < 0 ?
- AV_NOMEM : (errno = old, AV_DATAERR);
- }
- #endif
- // for dcl[] debug (duplicates key, ambiguous name)
- static int
- av_check_dcl (AV_DCLOPT_T *dcl, FILE *out)
- {
- int i, j, err = 0;
- for (i = 0; !ISEMPTY_DCL(dcl + i + 1); i++) {
- int c = dcl[i].key;
- if (c < 0 || c >= AV_KEY_SPEC) {
- err++;
- fprintf(out, "invalid key value %d (0x%02x) in dcl[] %d\n", c, c, i);
- }
- for (j = i + 1; !ISEMPTY_DCL(dcl + j); j++) {
- if (c > 0 && c == dcl[j].key) {
- fprintf(out, "key %d ('%c') duplicated in dcl[] %d and %d\n",
- c, Isgraph(c) ? c : 0, i, j);
- err++;
- }
- if (dcl[i].name && dcl[j].name && !strcmp(dcl[i].name, dcl[j].name)) {
- fprintf(out, "name '%s' duplicated in dcl[] %d and %d\n",
- dcl[i].name, i, j);
- err++;
- }
- }
- }
- return err;
- }
- static int
- _av_initcheck (struct av_state *st)
- {
- int rc = 0, urc;
- #ifndef unix
- _av_setwinprogname();
- #endif
- if (!st || !st->dcl) {
- fprintf(stderr, "%s: invalid usage (null state data)\n", __progname);
- return AV_USAGE_ERROR;
- }
- st->zopt = AV_KEY_NONE;
- st->optopt = 0;
- if (!st->out)
- st->out = stderr;
- if (st->optind < 1) { // rescan
- st->optind = !(st->flags & AV_PARSE_ARGV0);
- st->optchr = 0;
- }
- // OLD... st->msg = 0; // error message from dcl[].uvfun() must be malloc
- st->do_msg = 1;
- st->optlen = 0;
- st->dclindex = st->cur_argind = st->cur_optind = st->cur_optchr = -1;
- st->optsrc = st->optarg = NULL;
- if (st->optchr < 0) // fix possible user error?
- st->optchr = 0;
- if (!st->args)
- st->msg = 0;
- else
- free(st->msg), st->msg = 0;
- if (st->argc < 1 || !st->argv)
- return AV_ARGV_ERROR;
- if (!st->args) { // init
- st->optind = !(st->flags & AV_PARSE_ARGV0);
- st->flags |= (getenv("POSIXLY_CORRECT") ? AV_STOP_NONOPT_ARG : 0);
- st->optchr = 0;
- st->n_err = st->tot_err = st->n_opts = st->n_args = 0;
- st->arg_tail = -1;
- st->groups = -1; // all possible groups
- st->args = (char **)calloc(1, sizeof(*st->args));
- st->iargs = (int *)calloc(1, sizeof(*st->iargs));
- st->opts = (typeof(st->opts))calloc(1, sizeof(*st->opts));
- st->eropts = (typeof(st->eropts))calloc(1, sizeof(*st->eropts));
- if (!st->args || !st->opts || !st->eropts)
- return AV_NOMEM;
- AV_DCLOPT_T *dcl = st->dcl;
- if ((st->flags & AV_CHECK_DCL) && av_check_dcl(dcl, st->out) > 0) {
- fprintf(st->out, "%s: checkdcl() exit due to error\n", __progname);
- exit(EX_USAGE);
- }
- #ifndef AV_NOUSEVAR
- // check dcl[] array definition & types only up to first error
- for (st->dclindex = 0; !ISEMPTY_DCL(dcl); dcl++, st->dclindex++) {
- if ((urc = _av_check_arraydef(dcl, st)) < 0 && !rc)
- rc = urc; // will return first error code
- if (!_av_get_tsize(dcl->def_arg & AV_TYPE_MASK)) {
- urc = _av_type_error(dcl, st);
- if (!rc)
- rc = urc;
- }
- if (dcl->def_arg & AV_ISARRAY) {
- if (dcl->opt_counter)
- *(dcl->opt_counter) = 0;
- if (dcl->optarg_ptr)
- *(dcl->optarg_ptr) = 0;
- }
- if (dcl->uvfun && (urc = dcl->uvfun(AV_KEY_INIT, 0, st, dcl)) < 0) {
- st->tot_err++;
- if (!rc)
- rc = urc;
- }
- }
- st->dclindex = -1;
- #endif
- if (st->u_callback) {
- if ((urc = st->u_callback(AV_KEY_INIT, 0, st)) < 0) {
- st->tot_err++;
- if (!rc)
- rc = urc;
- }
- }
- }
- return rc;
- }
- // Check compatibility current option groups set with all groups,
- // if compatible modify all groups by current option groups
- static int
- _av_grcompat (int rc, struct av_state *st)
- {
- if ((0 < rc && rc < AV_KEY_SPEC) && st->dclindex >= 0) {
- int curopt_grp = AV_GROUPS(st->dcl + st->dclindex);
- if (curopt_grp) {
- if (st->groups & curopt_grp)
- st->groups &= curopt_grp;
- else
- rc = AV_NOCOMPATOPT;
- }
- }
- return rc;
- }
- // Main internal parsing routine
- // Returns av_dclopt.key or 0 (arg) or -1 (finish) or ERRCODE < -1
- static int
- _av_getopt (struct av_state *st)
- {
- int ret = _av_initcheck(st);
- if (ret)
- return ret;
- char **av = st->argv;
- int ac = st->argc, has_arg, key;
- AV_DCLOPT_T *dcl = st->dcl, *pdcl = dcl;
- for (;;) { // check current argv parsing point
- if (st->optind < ac)
- st->optsrc = av[st->optind];
- switch (_av_argtype(st, st->optind)) {
- case _AV_DASHDASH:
- st->optind++;
- case AV_END:
- return _av_clropt(AV_END, st); // no more arguments
- case AV_ARG:
- st->optarg = av[st->cur_argind = st->optind++];
- return _av_clropt(AV_ARG, st);
- }
- if (st->optchr < strlen(st->optsrc))
- break;
- _av_nextargv(st->zopt, st);
- }
- if (st->optchr == 0) { // check longopt
- st->cur_optchr = st->optchr = 1 + (av[st->optind][1] == '-');
- st->cur_optind = st->optind;
- // check first char is legal key and set st->dlcindex
- key = _av_findkey(dcl, st);
- char *optname = st->optsrc + st->optchr;
- if ((st->optlen = strcspn(optname, "="))
- && (st->optchr == 2 || st->flags & AV_LONGOPT_ONLY)) {
- // check for long option name
- char namebuf[st->optlen + 1];
- strncpy(namebuf, optname, st->optlen); namebuf[st->optlen] = 0;
- if (st->optchr == 2 // --option
- || !key // first char not recognized as short option
- || st->optlen > 1) { // but we want to recognize valid -longoption
- int i, match = 0;
- for (i = 0, pdcl = dcl; !ISEMPTY_DCL(pdcl); i++, pdcl++) {
- if (pdcl->key > 0 // must, by reason of return code 0 is ARG
- && pdcl->name
- && strncmp(optname, pdcl->name, st->optlen) == 0) {
- if (pdcl->name[st->optlen] == 0) { // exactly
- st->dclindex = i;
- match = 1;
- break;
- }
- if (!match++)
- st->dclindex = i; // first of not exactly matching
- }
- }
- if (match == 1) {
- pdcl = dcl + st->dclindex;
- st->zopt = ret = pdcl->key;
- if ((has_arg = pdcl->def_arg & AV_HASARG_MASK)) {
- if (optname[st->optlen] == '=') {
- st->cur_argind = st->optind;
- st->optarg = optname + st->optlen + 1;
- } else if (!(has_arg & AV_OPTARG)) { // not OPTARG, mandatory ARG
- if (st->optind + 1 < ac && st->argv[st->optind + 1]) {
- st->cur_argind = st->optind + 1;
- st->optarg = av[st->optind++ + 1];
- } else
- ret = AV_LONGOPT_REQ_ARG;
- }
- } else if (optname[st->optlen] == '=')
- ret = AV_LONGOPT_NOTALLOW_ARG;
- _av_nextargv(st->zopt, st);
- return _av_grcompat(ret, st);
- }
- if (match > 1) // BEFORE ./tt TEST && (st->optchr == 2 || !key))
- return _av_nextargv(AV_LONGOPT_AMBIGUOUS, st);
- if (st->optchr == 2 || (st->dclindex < 0 && st->optlen > 1))
- // Here "--longopt" or "-longopt" not found in dcl[]
- // and '-l' not found as short option too.
- // Note, when '-l' found as short option, we out of this point
- // and will try to parse "-longopt" as set of short options
- return _av_nextargv(AV_NO_LONGOPT, st);
- }
- }
- }
- ret = AV_NO_OPTION;
- st->optlen = 0; // short option
- st->optopt = st->optsrc[st->cur_optchr = st->optchr];
- st->cur_optind = st->optind;
- if ((key = _av_findkey(dcl, st))) {
- pdcl = dcl + st->dclindex;
- st->zopt = ret = pdcl->key;
- if ((has_arg = (pdcl->def_arg & AV_HASARG_MASK))) {
- if (st->optsrc[st->optchr + 1]) {
- // arg in the same argv, set data
- st->cur_argind = st->optind;
- st->optarg = st->optsrc + st->optchr + 1;
- _av_nextargv(ret, st); // will return pdcl->key
- } else if (!(has_arg & AV_OPTARG)) { // not OPTARG, mandatory ARG
- // data in the next argv and it required
- _av_nextargv(ret, st); // will return pdcl->key
- if (st->optind < ac && st->argv[st->optind]) {
- st->cur_argind = st->optind;
- st->optarg = av[st->optind++];
- } else
- ret = AV_OPTION_REQ_ARG;
- } else // optional_arg and data in the next argv[] (don't set it)
- st->optchr++;
- } else
- st->optchr++; // next step
- } else if (st->flags & AV_LONGOPT_ONLY)
- return _av_nextargv(AV_NO_LONGOPT, st);
- else
- st->optchr++; // here ret == AV_NO_OPTION i.e. invalid option
- return _av_grcompat(ret, st);
- }
- /*
- Create array res[] (call malloc()) with indexes of av_dclopt[],
- for .name matches avitem (if there are no matches, array not created)
- avitem must be --longopt or -longopt (with dashes!!!)
- Returns array size
- */
- static int
- av_match_names (char *avitem, AV_DCLOPT_T *dcl, int **res)
- {
- if (strlen(avitem) < 2 || *avitem != '-')
- return 0;
- char *optname = avitem + 1 + (avitem[1] == '-');
- int n = 0, match = 0, optlen = strcspn(optname, "=");
- *res = 0;
- for (n = 0; !ISEMPTY_DCL(dcl); dcl++, n++)
- if (dcl->name && dcl->name[0]
- && strncmp(optname, dcl->name, optlen) == 0)
- if (!av_addyna((char **)res, &match, (char *)&n, sizeof(n)))
- return -1;
- return match;
- }
- // returns message by code in malloc() memory
- static char *
- av_errormsg (struct av_state *st, int code)
- {
- AV_DCLOPT_T *dcl = 0;
- if (!st || !(dcl = st->dcl))
- code = AV_USAGE_ERROR;
- char *msg = 0;
- int dup = 1;
- switch (code) {
- case AV_ARG:
- msg = (char *)"the argument is not option"; break;
- case AV_END:
- msg = (char *)"finish"; break;
- case AV_BREAK:
- msg = (char *)"break by callback"; break;
- case AV_ANYERR:
- msg = (char *)"some error by callback"; break;
- case AV_NOMEM:
- msg = (char *)"out of memory"; break;
- case AV_USAGE_ERROR:
- msg = (char *)"invalid usage (null state or dcl)"; break;
- case AV_ARGV_ERROR:
- msg = (char *)"wrong arguments list"; break;
- case AV_LONGOPT_REQ_ARG:
- if (dup = (asprintf(&msg, "option '--%s' requires an argument",
- (dcl + st->dclindex)->name) < 0))
- msg = 0;
- break;
- case AV_LONGOPT_NOTALLOW_ARG:
- if (dup = (asprintf(&msg, "option '--%s' doesn't allow an argument",
- (dcl + st->dclindex)->name) < 0))
- msg = 0;
- break;
- case AV_LONGOPT_AMBIGUOUS:
- {
- char namebuf[strlen(st->optsrc) + 1];
- strcpy(namebuf, st->optsrc);
- namebuf[strcspn(namebuf, "=")] = 0;
- int sz = asprintf(&msg, "option '%s' is ambiguous; possibilities:",
- namebuf);
- if (sz < 0) {
- msg = 0; break;
- }
- int *amb = 0, n = av_match_names(st->optsrc, dcl, &amb), i;
- if (n < 0) {
- msg = 0; break;
- }
- for (i = 0; i < n; i++) {
- if (!(msg = (char *)realloc(msg,
- sz + strlen((dcl + amb[i])->name) + 6)))
- break;
- sz += sprintf(msg + sz, " '--%s'", (dcl + amb[i])->name);
- }
- if (n)
- free(amb);
- dup = 0;
- }
- break;
- case AV_NO_LONGOPT:
- {
- char namebuf[strlen(st->optsrc) + 1];
- if (st->optlen)
- strcpy(namebuf, st->optsrc);
- else {
- strcpy(namebuf + 1, st->optsrc + st->cur_optchr);
- namebuf[0] = '-';
- }
- namebuf[strcspn(namebuf, "=")] = 0;
- if (dup = (asprintf(&msg, "unrecognized option '%s'", namebuf) < 0))
- msg = 0;
- }
- break;
- case AV_NO_OPTION:
- if (dup = (asprintf(&msg, "invalid option -- '-%c'", st->optopt) < 0))
- msg = 0;
- break;
- case AV_OPTION_REQ_ARG:
- if (dup = (asprintf(&msg, "option '-%c' requires an argument",
- st->optsrc[st->cur_optchr]) < 0))
- msg = 0;
- break;
- case AV_NOCOMPATOPT:
- {
- char optbuf[2] = " ";
- if (!st->optlen)
- optbuf[0] = st->zopt;
- int sz = asprintf(&msg,
- "option '-%s%s' is not compatible with other options:",
- st->optlen ? "-" : "",
- st->optlen ? (dcl + st->dclindex)->name : optbuf),
- i;
- if (sz < 0) {
- msg = 0; break;
- }
- int curopt_grp = AV_GROUPS(dcl + st->dclindex);
- for (i = 0; i < st->n_opts; i++) {
- int grp = AV_GROUPS(dcl + st->opts[i].dclindex);
- if (grp && ((curopt_grp & grp) == 0)) {
- int l = st->opts[i].optlen;
- char opt[l ? l + 1 : 2];
- strncpy(opt, st->argv[st->opts[i].optind] + st->opts[i].optchr,
- l ? l : 1);
- opt[l ? l : 1] = 0;
- if (!(msg = (char *)realloc(msg, sz + l + 6)))
- break;
- sz += sprintf(msg + sz, " '%s%s'", l ? "--" : "-", opt);
- }
- }
- dup = 0;
- }
- break;
- case AV_DEFVAR:
- msg = (char *)"option declaration error"; break;
- case AV_DATAERR:
- msg = (char *)"option data format or value error"; break;
- default:
- if (dup = (asprintf(&msg, "Unknown error code %d", code) < 0))
- msg = 0;
- }
- return dup ? (msg ? strdup(msg) : 0) : msg;
- }
- #ifndef AV_NOUSEVAR
- static inline int
- _av_outof_urange (long long ll, int size)
- {
- int shift = size * CHAR_BIT, sign = ll & (1 << (shift - 1));
- ll >>= shift;
- return (ll && ll != -1) || (ll == -1 && !sign);
- }
- static int
- _av_check_range (long long ll, int type, int size)
- {
- switch (type) {
- case _AV_INT8_T:
- if (ll < SCHAR_MIN || ll > SCHAR_MAX)
- errno = ERANGE;
- break;
- case _AV_INT16_T:
- if (ll < SHRT_MIN || ll > SHRT_MAX)
- errno = ERANGE;
- break;
- case _AV_INT32_T:
- if (ll < INT_MIN || ll > INT_MAX)
- errno = ERANGE;
- break;
- default:
- if (_av_outof_urange(ll, size))
- errno = ERANGE;
- }
- return errno ? 0 : 1;
- }
- static int
- _av_put_data (int res, struct av_state *st)
- {
- AV_DCLOPT_T *pdcl = st->dcl + st->dclindex;
- int rc,
- ok = 1,
- has_arg = pdcl->def_arg & AV_HASARG_MASK,
- type = pdcl->def_arg & AV_TYPE_MASK,
- tsize = _av_get_tsize(type);
- if (!tsize)
- return _av_type_error(pdcl, st);
- if ((rc = _av_check_arraydef(pdcl, st)))
- return rc;
- if (pdcl->opt_counter && !(pdcl->def_arg & AV_ISARRAY))
- (*pdcl->opt_counter)++; // counter for ARRAY will incr in av_addyna() later
- if (pdcl->optarg_ptr && st->optarg && has_arg != AV_NOARG) {
- union {
- double d;
- float f;
- long long ll;
- char *p;
- int i;
- short s;
- char c;
- } val;
- long long ll;
- char *ep;
- int save_errno = errno;
- errno = 0;
- switch (type) {
- case _AV_STR_T:
- val.p = st->optarg; break;
- case _AV_DOUBLE_T: case _AV_FLOAT_T:
- if (type == AV_FLOAT)
- val.f = strtof(st->optarg, &ep);
- else
- val.d = strtod(st->optarg, &ep);
- if (*ep || errno)
- return _av_data_error(pdcl, st->optarg, save_errno, st);
- break;
- default:
- ll = strtoll(st->optarg, &ep, 0); val.ll = ll;
- if (*ep || errno)
- return _av_data_error(pdcl, st->optarg, save_errno, st);
- if (!_av_check_range(val.ll, type, tsize))
- return _av_data_error(pdcl, st->optarg, save_errno, st);
- switch (type) {
- case _AV_INT8_T: case _AV_UINT8_T: val.c = ll; break;
- case _AV_INT16_T: case _AV_UINT16_T: val.s = ll; break;
- case _AV_INT32_T: case _AV_UINT32_T: val.i = ll;
- }
- }
- if (pdcl->def_arg & AV_ISARRAY)
- ok = av_addyna(pdcl->optarg_ptr, pdcl->opt_counter,
- (char *)&val, tsize);
- else
- memcpy(pdcl->optarg_ptr, &val, tsize);
- }
- return ok ? res : AV_NOMEM;
- }
- #endif
- static void
- _av_set_avopt (struct av_opt *opt, struct av_state *st)
- {
- opt->optind = st->cur_optind;
- opt->optchr = st->cur_optchr;
- opt->optlen = st->optlen;
- opt->dclindex = st->dclindex;
- opt->argind = st->cur_argind;
- opt->dcl = st->dcl;
- opt->argchr = (opt->arg = st->optarg) ?
- st->optarg - st->argv[st->cur_argind] : -1;
- }
- // Returns av_dclopt.key or 0 (arg) or -1 (finish) or ERRCODE < -1
- static int
- av_getopt (struct av_state *st)
- {
- #ifndef unix
- _av_setwinprogname();
- #endif
- AV_DCLOPT_T *dcl;
- if (!st || !(dcl = st->dcl)) {
- fprintf(stderr, "%s: invalid usage (%s)\n",
- __progname, st ? "null dcl" : "null state");
- return AV_USAGE_ERROR;
- }
- st->dcl_itemsize = sizeof(*dcl);
- int ret = _av_getopt(st);
- if (ret == AV_ARG) {
- if (st->optind > 1 && (st->flags & AV_STOP_NONOPT_ARG))
- ret = _av_copytail(st, st->cur_argind);
- else if (!_av_add_arg(st, st->cur_argind))
- ret = AV_NOMEM;
- }
- #ifndef AV_NOUSEVAR
- if (st->dclindex >= 0 && dcl[st->dclindex].key) {
- if (AV_ARG < ret && ret < AV_KEY_SPEC)
- ret = _av_put_data(ret, st); // *opt_counter, *optarg_ptr changes here
- if (dcl[st->dclindex].uvfun)
- ret = dcl[st->dclindex].uvfun(ret, st->optarg, st, dcl + st->dclindex);
- }
- #endif
- if (st->u_callback)
- ret = st->u_callback(ret, st->optarg, st);
- if (ret == AV_END)
- ret = _av_copytail(st, st->optind); // AV_NOMEM possible
- struct av_opterr t;
- t.opt.optlen = -1; // indicator that t.opt is not fill yet
- // char *msg = st->msg; // any message from callback() must be malloc
- // st->msg = 0;
- if (0 < ret && ret < AV_KEY_SPEC) { //add opt
- _av_set_avopt(&t.opt, st);
- if (!_av_store_opts(&st->n_opts, (void **)&st->opts,
- (void **)&t.opt, sizeof(t.opt), _av_cmp_optpos))
- ret = AV_NOMEM;
- }
- if (ret < 0 && ret != AV_END && ret != AV_BREAK) { // add erropt & error msg
- st->tot_err++;
- if (t.opt.optlen == -1)
- _av_set_avopt(&t.opt, st);
- t.errcode = ret;
- if (st->do_msg) {
- // callback don't add own final meassage
- char *msg = av_errormsg(st, ret);
- if (!msg || _av_addmsg(&st->msg, "%s", msg) < 0)
- ret = AV_NOMEM;
- free(msg);
- }
- switch (ret) {
- case AV_NOMEM:
- fprintf(st->out, "%s: out of memory\n", __progname);
- case AV_ARGV_ERROR:
- case AV_USAGE_ERROR:
- break;
- default:
- if (t.opt.optind < 0)
- break;
- t.errmsg = strdup(st->msg ? st->msg : (char *)"no msg");
- if (!_av_store_opts(&st->n_err, (void **)&st->eropts,
- (void **)&t, sizeof(t), _av_cmp_opterrpos)) {
- fprintf(st->out, "%s: out of memory\n", __progname);
- ret = AV_NOMEM;
- }
- }
- }
- #ifndef AV_NOUSEVAR
- if (0 < ret && ret < AV_KEY_SPEC)
- (dcl + st->dclindex)->processed = st->optsrc; //argv[st->cur_optind];
- else if (ret == AV_END || ret == AV_BREAK)
- for (; !ISEMPTY_DCL(dcl); dcl++) {
- if (dcl->uvfun && dcl->uvfun(AV_KEY_FINI, 0, st, dcl) < 0)
- st->tot_err++;
- }
- #endif
- if ((ret == AV_END || ret == AV_BREAK) && st->u_callback) {
- if (st->u_callback(AV_KEY_FINI, 0, st) < 0)
- st->tot_err++;
- }
- if (st->msg && !(st->flags & AV_SILENT)) {
- // fprintf(st->out, "%s: %s\n", __progname, st->msg);
- int l = fprintf(st->out, "%s: ", __progname);
- char *t = st->msg, filler[l + 1], c;
- memset(filler, ' ', l); filler[l] = 0;
- while (c = *t++) {
- fputc(c, st->out);
- if (c == '\n')
- fputs(filler, st->out);
- }
- fputc('\n', st->out);
- }
- if (st->tot_err &&
- ((st->flags & AV_ERREXIT) ||
- ((ret == AV_END || ret == AV_BREAK) && (st->flags & AV_ERRENDEXIT)))) {
- if (!(st->flags & AV_SILENT)) {
- if (!(st->flags & AV_QUIET_EXIT)) {
- av_opt_usage(dcl, 0, 0, st->out);
- fprintf(st->out, "%s: exit due to error(s)\n", __progname);
- }
- fprintf(st->out, "Try `%s --help or --usage` for more information.\n",
- __progname);
- }
- exit(EX_USAGE);
- }
- return ret;
- }
- static struct av_state *
- argvopt (int ac, char *av[], AV_DCLOPT_T *dcl,
- FILE *out, int flags, ucallback_t uf, void *glue)
- {
- #ifndef unix
- _av_setwinprogname();
- #endif
- struct av_state st = {0}, *res;
- AV_DCLOPT_T dd[] = {{0}};
- st.dcl = dcl ? dcl : dd;
- st.argc = ac;
- st.argv = av;
- st.flags = flags;
- st.out = out;
- st.glue = glue;
- st.u_callback = uf;
- int opt;
- while ((opt = av_getopt(&st)) != AV_END)
- if (opt == AV_BREAK ||
- opt == AV_USAGE_ERROR ||
- opt == AV_ARGV_ERROR ||
- opt == AV_NOMEM ||
- (st.tot_err && (st.flags & AV_ERRBREAK)))
- break;
- st.dcl = dcl; // may restore NULL
- if ((res = (typeof(res))malloc(sizeof(*res))))
- memcpy(res, &st, sizeof(st));
- return res;
- }
- static void *
- av_state_free (struct av_state *st, int free_st)
- {
- if (st->args) {
- free(st->args);
- free(st->iargs);
- free(st->opts);
- int i;
- for (i = 0; i < st->n_err; i++)
- free(st->eropts[i].errmsg);
- free(st->eropts);
- free(st->msg);
- }
- if (free_st)
- free(st);
- else
- memset(st, 0, sizeof(*st));
- return 0;
- }
- /*
- help/usage
- */
- static const char *av_program_doc;
- static const char *av_program_usage_doc;
- static const char *av_args_doc = "[ARG ...]";
- static const char *av_program_version = "argvopt 1.1";
- //static const char *av_exitcode;
- #ifndef AV_WRAP_LINE
- #define AV_WRAP_LINE 64
- #endif
- static int av_wrap_pos = AV_WRAP_LINE;
- #define DEFAULT_ARGNAME "ARG"
- #ifndef DESCR_POS
- #define DESCR_POS 26
- #endif
- static const char *
- _av_print_begin (const char *beg_end_msg, FILE *out)
- {
- int c = 0;
- if (beg_end_msg)
- while ((c = *beg_end_msg++) && c != '\v')
- fputc(c, out);
- return c ? beg_end_msg : 0;
- }
- static char *
- _av_get_argname (const char *descr, char *argname, int size)
- {
- const char *p = DEFAULT_ARGNAME, *q = descr ? strchr(descr, '\v') : 0;
- char *a = argname;
- if (q)
- p = q + 1;
- while ((size-- > 1) && (*a++ = *p++));
- *a = 0;
- return argname;
- }
- static int
- _av_print_description (int l, AV_DCLOPT_T *dcl, FILE *out, int prigroups)
- {
- const char *p = dcl->descr;
- if (p && *p && *p != '\v') {
- if (l) { // key or longoption or both was printed
- if (l > DESCR_POS - 1)
- fputc(' ', out), l++;
- for (; l < DESCR_POS; l++) // print pad spaces before description
- fputc(' ', out);
- int groups = prigroups ? AV_GROUPS(dcl) : 0;
- if (groups)
- l += fprintf(out, "<%02x> ", groups);
- else
- while (l++ < DESCR_POS + 5)
- fputc(' ', out);
- }
- while (*p && *p != '\v') {
- l++;
- fputc(*p++, out);
- }
- }
- return l;
- }
- static int
- _av_print_argname (int l, AV_DCLOPT_T *dcl, FILE *out)
- {
- if (l && (dcl->def_arg & AV_HASARG_MASK)) {
- char argname[80]; // default = "ARG";
- int oa = dcl->def_arg & AV_OPTARG;
- l += fprintf(out, "%s%s%s",
- oa ? dcl->name ? "[=" : "[" : " ",
- _av_get_argname(dcl->descr, argname, sizeof(argname)),
- oa ? "]" : "");
- }
- return l;
- }
- static inline int _av_wrap_line (int print_pos, FILE *out) {
- if (print_pos > av_wrap_pos) {
- print_pos = 8;
- fputs("\n\t", out);
- }
- return print_pos;
- }
- static int
- _av_priusgrp (AV_DCLOPT_T *dcl, long long gmask, int n_grp,
- int l, FILE *out, int mnd_fl, int *obl)
- {
- int i, grps;
- // print options
- for (i = 0; !ISEMPTY_DCL(dcl); dcl++, i++) {
- if (gmask == ~0 || i > 63
- || !(grps = AV_GROUPS(dcl)) || (gmask & (1LL << i))) {
- int mnd = AV_MANDAT(dcl),
- is_mandatory = (mnd == AV_VMANDAT(AV_MNDTRY))
- || (n_grp ? (mnd & (1 << (n_grp - 1))) : mnd);
- if (mnd_fl != is_mandatory) {
- (*obl)++;
- continue;
- }
- int key = Isgraph(dcl->key) ? dcl->key : 0;
- l = _av_wrap_line(l, out);
- if (dcl->def_arg & AV_HASARG_MASK) {
- char argname[80];
- int oa = dcl->def_arg & AV_OPTARG;
- if (key)
- l += dcl->name ?
- fprintf(out, " -%c,", key) :
- fprintf(out, " -%c%s%s%s", key, oa ? "[" : " ",
- _av_get_argname(dcl->descr, argname, sizeof(argname)),
- oa ? "]" : "");
- if (dcl->name)
- l += fprintf(out, "%s--%s%s%s%s", key ? "" : " ",
- dcl->name, oa ? "[=" : "=",
- _av_get_argname(dcl->descr, argname, sizeof(argname)),
- oa ? "]" : "");
- } else {
- if (key)
- l += fprintf(out, " -%c%s", key, dcl->name ? "," : "");
- if (dcl->name)
- l += fprintf(out, "%s--%s", key ? "" : " ", dcl->name);
- }
- }
- }
- return l;
- }
- static void
- _av_pri_usage_group (AV_DCLOPT_T *dcl, long long gmask, int n_grp,
- int l, const char *args_msg, FILE *out)
- {
- int n_obl = 0;
- l = _av_priusgrp(dcl, gmask, n_grp, l, out, 1, &n_obl); // print mandatory
- if (n_obl) {
- fputs(" [", out);
- l = _av_priusgrp(dcl, gmask, n_grp, l + 2, out, 0, &n_obl) + 2;
- fputs(" ]", out);
- }
- if (args_msg) {
- fflush(out);
- if (l + strcspn(args_msg, "\n\001\002\003\004\005\006\007\008") > 79)
- fputs("\n\t", out);
- fputc(' ', out);
- while ((unsigned char)*args_msg > AV_GRP_LEN)
- fputc(*args_msg++, out);
- }
- fputc('\n', out);
- }
- static const char *
- _av_getgroup_arg (const char *args_msg, int group)
- {
- if (args_msg && group) {
- while (*args_msg && *args_msg != group)
- args_msg++;
- if (*args_msg)
- args_msg++;
- }
- return args_msg;
- }
- static void
- _av_set_index_bitmask (long long bitmask[], int index, int grps)
- {
- int j;
- if (grps) // this DCL in one or more groups
- for (j = 0; j < AV_GRP_LEN; j++)
- if (grps & (1 << j))
- bitmask[j] |= (1LL << index);
- }
- static void
- _av_print_usage (AV_DCLOPT_T *dcl, const char *args_msg, FILE *out)
- {
- #ifndef unix
- _av_setwinprogname();
- #endif
- long long groups[AV_GRP_LEN] = {0}; // bitmasks of DCL indexes by groups
- // mandat[AV_GRP_LEN] = {0}; // the same for mandatory in group
- int i, j, n = 0, call = 0, grp;
- for (i = 0; i < 64 && !ISEMPTY_DCL(dcl + i); i++)
- _av_set_index_bitmask(groups, i, AV_GROUPS(dcl + i));
- // remove duplicates
- for (i = AV_GRP_LEN - 1; i >= 0; i--)
- if (groups[i]) {
- n++;
- for (j = 0; j < i; j++)
- if (groups[i] == groups[j]) {
- groups[i] = 0;
- n--;
- break;
- }
- }
- if (!n)
- groups[0] = ~0; // no one, so let all DCL belongs to first (special) group
- for (i = 0; i < AV_GRP_LEN; i++)
- if (groups[i]) {
- int n_grp = groups[i] == ~0 ? 0 : i + 1;
- _av_pri_usage_group(dcl, groups[i], n_grp,
- n > 1 ?
- fprintf(out,
- ++call == 1 ? "Usage: (%d) %s" : " or : (%d) %s",
- n_grp, __progname) :
- fprintf(out, "Usage: %s", __progname),
- _av_getgroup_arg(args_msg, n_grp), out);
- }
- }
- static void
- av_opt_usage (AV_DCLOPT_T *dcl,
- const char *beg_end_msg, const char *args_msg, FILE *out)
- {
- if (!out)
- out = stderr;
- if (!beg_end_msg)
- beg_end_msg = av_program_usage_doc;
- if (!args_msg)
- args_msg = av_args_doc;
- beg_end_msg = _av_print_begin(beg_end_msg, out);
- _av_print_usage(dcl, args_msg, out);
- if (beg_end_msg) // print END part
- fprintf(out, "%s\n", beg_end_msg);
- }
- static void
- _av_opt_help (AV_DCLOPT_T *dcl, const char *beg_end_msg, const char *args_msg,
- FILE *out, int priusage, int prigroups)
- {
- if (!out)
- out = stderr;
- if (!beg_end_msg)
- beg_end_msg = av_program_doc;
- if (!args_msg)
- args_msg = av_args_doc;
- beg_end_msg = _av_print_begin(beg_end_msg, out);
- if (priusage)
- _av_print_usage(dcl, args_msg, out);
- int bla = 0;
- for (; !ISEMPTY_DCL(dcl); dcl++) {
- int l = Isgraph(dcl->key) ?
- fprintf(out, " -%c%s", dcl->key, dcl->name ? "," : "") : 0;
- l += dcl->name ? fprintf(out, "%s --%s", l ? "" : " ", dcl->name) : 0;
- if (_av_print_description(_av_print_argname(l, dcl, out),
- dcl, out, prigroups))
- fputc('\n', out);
- if (Isgraph(dcl->key) && dcl->name && (dcl->def_arg & AV_HASARG_MASK))
- bla++;
- }
- if (bla)
- fprintf(out, "\n"
- "Mandatory or optional arguments to long options are also "
- "mandatory or optional for any corresponding short options."
- "\n%s", beg_end_msg ? "\n" : "");
- if (beg_end_msg) // print END part
- fprintf(out, "%s\n", beg_end_msg);
- }
- static void
- av_opt_help (AV_DCLOPT_T *dcl,
- const char *beg_end_msg, const char *args_msg, FILE *out)
- {
- _av_opt_help(dcl, beg_end_msg, args_msg, out, 1 /* print usage */, 1);
- }
- static void
- av_opt_help2 (AV_DCLOPT_T *dcl, const char *beg_end_msg, const char *args_msg,
- FILE *out, int prigroups)
- {
- _av_opt_help(dcl, beg_end_msg, args_msg, out, 0 /* no usage */, prigroups);
- }
- #ifndef AV_NOUSEVAR
- // dcl[] uvfun()s for usage & help
- static int
- av_dcl_usage (int key, char *a, struct av_state *st, AV_DCLOPT_T *td) {
- // if (key > 0 && key != AV_KEY_INIT && key != AV_KEY_FINI) {
- if (td && td->key == key) {
- av_opt_usage(st->dcl, (char *)td->arg1, (char *)td->arg2, 0);
- if (td->optarg_ptr)
- exit(atoi((char *)td->optarg_ptr));
- }
- return key;
- }
- // full help
- static int
- av_dcl_help1 (int key, char *a, struct av_state *st, AV_DCLOPT_T *td) {
- // if (key > 0 && key != AV_KEY_INIT && key != AV_KEY_FINI) {
- if (td && td->key == key) {
- av_opt_help(st->dcl, (char *)td->arg1, (char *)td->arg2, 0);
- if (td->optarg_ptr)
- exit(atoi((char *)td->optarg_ptr));
- }
- return key;
- }
- // full help without groups
- static int
- av_dcl_help (int key, char *a, struct av_state *st, AV_DCLOPT_T *td) {
- // if (key > 0 && key != AV_KEY_INIT && key != AV_KEY_FINI) {
- if (td && td->key == key) {
- _av_opt_help(st->dcl, (char *)td->arg1, (char *)td->arg2,
- st->out, 1, 0);
- if (td->optarg_ptr)
- exit(atoi((char *)td->optarg_ptr));
- }
- return key;
- }
- // help without usage() and options groups info (opt description list)
- static int
- av_dcl_help2 (int key, char *a, struct av_state *st, AV_DCLOPT_T *td) {
- // if (key > 0 && key != AV_KEY_INIT && key != AV_KEY_FINI) {
- if (td && td->key == key) {
- av_opt_help2(st->dcl, (char *)td->arg1, (char *)td->arg2, 0, 0);
- if (td->optarg_ptr)
- exit(atoi((char *)td->optarg_ptr));
- }
- return key;
- }
- // print version
- static int
- av_dcl_version (int key, char *a, struct av_state *st, AV_DCLOPT_T *td) {
- // if (key > 0 && key != AV_KEY_INIT && key != AV_KEY_FINI) {
- if (td && td->key == key) {
- puts(av_program_version);
- if (td->optarg_ptr)
- exit(atoi((char *)td->optarg_ptr));
- }
- return key;
- }
- /*
- misc debug
- */
- #include <signal.h>
- #include <setjmp.h>
- #include <fcntl.h>
- #ifndef unix
- #define sigjmp_buf jmp_buf
- #define siglongjmp longjmp
- #define sigsetjmp(buf,flag) setjmp(buf)
- #endif
- #ifdef __cplusplus
- static sigjmp_buf _av_is_accessible_jmp;
- static void _av_is_accessible_hdr (int sig) {
- siglongjmp(_av_is_accessible_jmp, 0);
- }
- #endif
- // check is addr readable/writable, returns 1 if so
- static int
- _av_is_mem_accessible (char *addr, int writable)
- {
- if (addr == 0 || addr == (void *)-1LL)
- return 0;
- int rc = 1;
- #ifndef __cplusplus
- sigjmp_buf _av_is_accessible_jmp;
- void _av_is_accessible_hdr (int sig) { siglongjmp(_av_is_accessible_jmp, 0); }
- #endif
- void
- #ifdef unix
- (* sigbus)(int) = signal(SIGBUS, _av_is_accessible_hdr),
- #endif
- (* sigsegv)(int) = signal(SIGSEGV, _av_is_accessible_hdr);
- #ifdef DEBUG
- #ifdef unix
- if (sigbus == SIG_ERR) {
- fputs ("SIG_ERR signal SIGBUS\n", stderr);
- exit(1);
- }
- #endif
- if (sigsegv == SIG_ERR) {
- fputs ("SIG_ERR signal SIGSEGV\n", stderr);
- exit(1);
- }
- #endif
- if (sigsetjmp(_av_is_accessible_jmp, 1)) { // MANDATORY save sigmask
- rc = 0;
- errno = EINVAL;
- } else {
- char t = *addr;
- if (writable)
- *addr = t;
- }
- #ifdef unix
- signal(SIGBUS, sigbus);
- #endif
- signal(SIGSEGV, sigsegv);
- return rc;
- }
- static void
- _av_print_value (void *ptr, int type, FILE *out)
- {
- union {
- double d;
- float f;
- long long ll;
- char *p;
- int i;
- short s;
- char c;
- } *pv = (typeof(pv))ptr;
- int64_t ll = pv->ll;
- int unsign = 0;
- switch (type) {
- case _AV_STR_T:
- fprintf(out, "[%s]", _av_is_mem_accessible(pv->p, O_RDONLY) ?
- pv->p : pv->p ? "(N/A)" : "(null)");
- break;
- case _AV_DOUBLE_T:
- fprintf(out, "%.16g", pv->d);
- break;
- case _AV_FLOAT_T:
- fprintf(out, "%f", pv->f);
- break;
- default:
- switch (type) {
- case _AV_INT8_T: ll = pv->c; break;
- case _AV_INT16_T: ll = pv->s; break;
- case _AV_INT32_T: ll = pv->i; break;
- case _AV_UINT8_T: unsign = 1; ll = (uint8_t)pv->c; break;
- case _AV_UINT16_T: unsign = 1; ll = (uint16_t)pv->s; break;
- case _AV_UINT32_T: unsign = 1; ll = (uint32_t)pv->i; break;
- case _AV_UINT64_T: unsign = 1;
- }
- if (unsign)
- fprintf(out, "%llu", (unsigned long long)ll);
- else
- fprintf(out, "%lld", (long long)ll);
- }
- }
- static void
- av_print_dcl (AV_DCLOPT_T *dp, FILE *out)
- {
- if (!out)
- out = stdout;
- for (; !ISEMPTY_DCL(dp); dp++) {
- if (dp->key <= 0)
- continue;
- if (dp->name)
- fprintf(out, "%s:\t%s", dp->name, strlen(dp->name) < 7 ? "\t" : "");
- else if (Isgraph(dp->key))
- fprintf(out, "'%c':\t\t", dp->key);
- else
- fprintf(out, "0x%04x:\t\t", dp->key);
- if (dp->processed)
- fprintf(out, "'%s'\t%s",
- dp->processed, strlen(dp->processed) < 7 ? "\t" : "");
- else
- fputs(" not used \t", out);
- if (_av_is_mem_accessible((char *)dp->opt_counter, O_RDONLY))
- fprintf(out, "cnt: %d\t", *dp->opt_counter);
- else
- fprintf(out, " \t");
- if (dp->def_arg & AV_HASARG_MASK) {
- if (_av_is_mem_accessible((char *)dp->optarg_ptr, O_RDONLY)) {
- int type = dp->def_arg & AV_TYPE_MASK,
- vsize = _av_get_tsize(type), i;
- if (vsize)
- if (dp->def_arg & AV_ISARRAY) {
- if (_av_is_mem_accessible((char *)dp->opt_counter, O_RDONLY)) {
- char *ap = *dp->optarg_ptr;
- for (i = 0; i < *dp->opt_counter; i++) {
- _av_print_value((ap + i * vsize), type, out);
- fputc(' ', out);
- }
- } else
- fprintf(out, "ERR: no counter for array");
- } else
- _av_print_value(dp->optarg_ptr, type, out);
- else
- fprintf(out, "ERR: unknown type");
- } else
- fprintf(out, "[%s]",
- dp->optarg_ptr ? "<N/A>" : "ERR: no pointer to array");
- }
- fputc('\n', out);
- }
- }
- #endif // AV_NOUSEVAR
- #endif // #ifndef AV_NOCODE
- #endif // _ARGVOPT_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement