diff options
author | Ulrich Drepper <drepper@redhat.com> | 1997-02-15 04:31:36 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1997-02-15 04:31:36 +0000 |
commit | c84142e8fe3cbcce43ae35ac957a74ac8216d11d (patch) | |
tree | da310b5d0928e6dab9d1195606a4b56376ae747c /argp/argp-parse.c | |
parent | 7434ccadbb6897d366d2377f84efe1e2cd61b02b (diff) |
Update to 2.1.x development versioncvs/libc-970218cvs/libc-970217cvs/libc-970216cvs/libc-970215
1997-02-15 02:41 Miles Bader <miles@gnu.ai.mit.edu>
* argp/argp-help.c: Gettextize sources.
* argp/argp-parse.c: Likewise.
1997-02-13 22:32 Ulrich Drepper <drepper@cygnus.com>
* features.h (__GLIBC_MINOR__): Bump to 1.
* xlocale.h: New file. Wrapper around locale/xlocale.h.
* Makefile (distribute): Add xlocale.h.
* locale/Makefile (routines): Add ctype_l.
* locale/ctype-extn.c: Update copyright. De-ANSI-declfy.
Add __isblank_l, __toascii_l and __isascii_l.
* ctype/ctype.h: Add definitions and declarations for *_l functions.
* locale/Makefile (headers): Add xlocale.h.
(routines): Add newlocale, duplocale, and freelocale.
* locale/localeinfo.h (MAX_USAGE_COUNT): New macro.
(struct locale_data): Add new fields mmaped and usage_count.
Correct various declarations.
* locale/C-collate.c: Define value for new fields mmaped and
usage_count.
* locale/C-ctype.c: Likewise.
* locale/C-messages.c: Likewise.
* locale/C-monetary.c: Likewise.
* locale/C-numeric.c: Likewise.
* locale/C-time.c: Likewise.
* locale/loadlocale.c (_nl_load_locale): Initialize mmaped and
usage_count fields.
* locale/locale.h: Don't define locale_t here (moved to xlocale.h).
Correct prototypes for __newlocale and __freelocale.
Add prototype for __duplocale.
* locale/findlocale.c (copy): Remove function. Use __strdup instead.
(_nl_remove_locale): New function.
* locale/nl_langinfo.c: Don't declare locale_data objects as const.
* locale/setlocale.c: Likewise.
* locale/weight.h: Change for use with locale objects.
* locale/xlocale.h: New file. Define __locale_t type.
* locale/newlocale.c: New file. Create new locale object.
* locale/freelocale.c: New file. Destroy locale object.
* locale/duplocale.c: New file. Create copy of locale object.
* stdlib/Makefile (routines): Add strfmon_l.
* stdlib/monetary.h [__USE_GNU]: Declare __strfmon_l.
* stdlib/strfmon.c: Add support for use in extended locale model.
* stdlib/strfmon_l.c: New file.
* string/Makefile (routines): Add strcoll_l and strxfrm_l.
* string/strcoll.c: Change for use in extended locale model.
* string/strxfrm.c: Likewise.
* string/strcoll_l.c: New file. Implement __strcoll_l function.
* string/strxfrm_l.c: New file. Implement __strxfrm_l function.
* wcsmbs/Makefile (routines): Add wcscoll_l and wcsxfrm_l.
* wcsmbs/wchar.h [__USE_GNU]: Declare wcscoll_l and wcsxfrm_l.
* wcsmbs/wcscoll.c: Change for use in extended locale model.
* wcsmbs/wcscoll_l.c: New file. Implement __wcscoll_l function.
* wcsmbs/wcsxfrm_l.c: New file. Implement __wcsxfrm_l function.
* wctype/Makefile (routines): Add wcextra, wcfuncs_l, iswctype_l,
and towctrans_l.
* wctype/cname-lookup.h: Prepare for use in extended locale model.
* wctype/iswctype_l.c: New file. Implement character classification
functions for use with locale objects.
* wctype/wctype.h: Declare functions for use with locale objects.
* wctype/towctrans_l.c: New file. Implement __towctrans_l function
for use with locale objects.
* wctype/wcfuncs_l.c: New file. Implement wide character
classification functions for use with locale objects.
* wctype/wcextra.c: New file. Implement real functions for
non-standard classification functions.
* elf/ldd.bash.in: Don't use --data-relocs and --function-relocs
parameters to ld.so. Use environment variables.
* elf/ldd.sh.in: Likewise.
* elf/rtld.c: Remove handling of --data-relocs and --function-relocs
options. Instead read environment variables.
* elf/link.h (receiver_fct): Add new argument to take error code.
* elf/dl-error.c (_dl_signal_error): Call receiver function with
another argument.
* elf/dl-object.c (_dl_new_object): Create new object with list of
names in l_libname member.
* elf/dl-load.c (_dl_map_object_from_fd): Add name which was used to
find to object to the list in the link_map variable.
(_dl_map_object): Use _dl_does_name_match_p to compare with all
available names of the object.
Optimize handling of LD_LIBRARY_PATH a bit.
* elf/rtld.c: Initialize l_libname member of _dl_rtld_map.
* elf/dl-lookup.c (_dl_elf_hash): Optimize function.
* elf/Makefile (routines): Add dl-version.
* elf/link.h (hash_name_pair): New type. Group pointer to string
and its hash value.
(struct link_map): Change l_libname member to be a list of names,
not a single pointer to a name.
Add new members l_nversions and l_versions.
(_dl_does_name_match_p): New function to test for all names of an
object.
Add prototypes for new lookup and versioning functions.
* elf/dl-lookup.c (do_lookup): Add new argument and handle case
when versioned symbol is requested.
(_dl_lookup_symbol): Call do_lookup with another argument.
(_dl_lookup_symbol_skip): Likewise.
(_dl_lookup_versioned_symbol): New function. Handle lookup of
versioned symbol.
(_dl_lookup_versioned_symbol_skip): Likewise, similar to
_dl_lookup_symbol_skip.
* elf/dl-reloc.c (RESOLVE): Call _dl_lookup_versioned_symbol or
_dl_lookup_symbol depending on availability of version information.
* elf/dl-runtime.c (RESOLVE): Likewise.
(fixup): Call elf_machine_relplt with additional argument to point
to versioning information if available.
* elf/do-rel.h (elf_dynamic_do_rel): Likewise.
* elf/dl-open.c (_dl_open): Call _dl_check_map_versions to check
for correct versions.
* elf/dl-version.c: New file. Check library versions and extract
version information for easier access.
* elf/dlfcn.h [__USE_GNU]: Add prototype for dlvsym.
* elf/dlvsym.c: New file. Implementation of function similar to
dlsym, but looks for versioned symbol.
* elf/elf.h: Add types and macros for versioning.
* elf/rtld.c (dl_main): Check availability of needed versions.
* sysdeps/alpha/dl-machine.h (elf_machine_rela): Add additional
argument for version information. Call RESOLVE with additional
argument.
* sysdeps/i386/dl-machine.h: Likewise.
* sysdeps/m68k/dl-machine.h: Likewise.
* sysdeps/mips/dl-machine.h: Likewise.
* elf/dlerror.c: Change comment to align with guidelines.
* elf/dlopen.c: Likewise.
* elf/dlsym.c: Likewise.
* locale/programs/localedef.c: Implement --quiet option.
* locale/programs/charset.h: Declare be_quiet variable.
* locale/programs/locfile.h: Likewise.
* locale/programs/charmap.c: Don't print warnings if quiet option
was given.
* locale/programs/ld-collate.c: Likewise.
* locale/programs/ld-ctype.c: Likewise.
* locale/programs/ld-messages.c: Likewise.
* locale/programs/ld-monetary.c: Likewise.
* locale/programs/ld-numeric.c: Likewise.
* locale/programs/ld-time.c: Likewise.
* locale/programs/locfile.c: Likewise.
* Makefile (subdirs): Add argp.
* catgets/catgets.c (catopen): Little code improvement.
* posix/execl.c: Remove restriction to 1024 arguments.
* posix/execle.c: Likewise.
* posix/execlp.c: Likewise.
* posix/getopt.c [_LIBC]: Define global objects with __ prefix
and make regular names weak aliases.
* posix/getopt1.c: Likewise.
* posix/getopt.h [_LIBC]: Provide prototypes and declarations for
__ protected forms.
* posix/unistd.h: Add prototype for __sleep.
* sysdeps/mach/sleep.c: Make sleep weak alias of __sleep.
* sysdeps/posix/sleep.c: Likewise.
* sysdeps/stub/sleep.c: Likewise.
* sysdeps/unix/sysv/linux/sleep.c: Likewise.
* ctype/ctype-info.c: Update copyright.
* ctype/ctype.c: Likewise.
* ctype/test_ctype.c: Likewise.
* dirent/alphasort.c: Likewise.
* dirent/list.c: Likewise.
* gmon/bb_exit_func.c: Likewise.
* grp/fgetgrent.c: Likewise.
* grp/getgrent.c: Likewise.
* grp/getgrent_r.c: Likewise.
* grp/getgrgid.c: Likewise.
* grp/getgrgid_r.c: Likewise.
* grp/getgrnam.c: Likewise.
* grp/getgrnam_r.c: Likewise.
* hurd/alloc-fd.c: Likewise.
* hurd/catch-exc.c: Likewise.
* hurd/ctty-input.c: Likewise.
* hurd/ctty-output.c: Likewise.
* hurd/dtable.c: Likewise.
* hurd/fchroot.c: Likewise.
* hurd/fd-close.c: Likewise.
* hurd/fd-read.c: Likewise.
* hurd/fd-write.c: Likewise.
* hurd/fopenport.c: Likewise.
* hurd/get-host.c: Likewise.
* hurd/getdport.c: Likewise.
* hurd/getuids.c: Likewise.
* hurd/getumask.c: Likewise.
* hurd/hurd-raise.c: Likewise.
* hurd/hurd.h: Likewise.
* hurd/hurdauth.c: Likewise.
* hurd/hurdexec.c: Likewise.
* hurd/hurdhost.h: Likewise.
* hurd/hurdid.c: Likewise.
* hurd/hurdinit.c: Likewise.
* hurd/hurdioctl.c: Likewise.
* hurd/hurdkill.c: Likewise.
* hurd/hurdlookup.c: Likewise.
* hurd/hurdmsg.c: Likewise.
* hurd/hurdpid.c: Likewise.
* hurd/hurdports.c: Likewise.
* hurd/hurdprio.c: Likewise.
* hurd/hurdrlimit.c: Likewise.
* hurd/hurdsock.c: Likewise.
* hurd/hurdstartup.c: Likewise.
* hurd/hurdstartup.h: Likewise.
* hurd/intern-fd.c: Likewise.
* hurd/intr-msg.c: Likewise.
* hurd/intr-rpc.defs: Likewise.
* hurd/intr-rpc.h: Likewise.
* hurd/msgportdemux.c: Likewise.
* hurd/new-fd.c: Likewise.
* hurd/openport.c: Likewise.
* hurd/pid2task.c: Likewise.
* hurd/port-cleanup.c: Likewise.
* hurd/port2fd.c: Likewise.
* hurd/ports-get.c: Likewise.
* hurd/ports-set.c: Likewise.
* hurd/privports.c: Likewise.
* hurd/report-wait.c: Likewise.
* hurd/set-host.c: Likewise.
* hurd/setauth.c: Likewise.
* hurd/setuids.c: Likewise.
* hurd/siginfo.c: Likewise.
* hurd/sigunwind.c: Likewise.
* hurd/task2pid.c: Likewise.
* hurd/thread-cancel.c: Likewise.
* hurd/thread-self.c: Likewise.
* hurd/vpprintf.c: Likewise.
* hurd/hurd/fd.h: Likewise.
* hurd/hurd/id.h: Likewise.
* hurd/hurd/ioctl.h: Likewise.
* hurd/hurd/lookup.h: Likewise.
* hurd/hurd/port.h: Likewise.
* hurd/hurd/resource.h: Likewise.
* hurd/hurd/threadvar.h: Likewise.
* hurd/hurd/userlink.h: Likewise.
* inet/ether_aton.c: Likewise.
* inet/ether_aton_r.c: Likewise.
* inet/ether_ntoa.c: Likewise.
* inet/ether_ntoa_r.c: Likewise.
* inet/gethstbyad.c: Likewise.
* inet/gethstbyad_r.c: Likewise.
* inet/gethstent.c: Likewise.
* inet/getnetbyad.c: Likewise.
* inet/getnetbyad_r.c: Likewise.
* inet/getnetbynm.c: Likewise.
* inet/getnetbynm_r.c: Likewise.
* inet/getnetent.c: Likewise.
* inet/getnetent_r.c: Likewise.
* inet/getproto.c: Likewise.
* inet/getproto_r.c: Likewise.
* inet/getprtent.c: Likewise.
* inet/getprtent_r.c: Likewise.
* inet/getprtname.c: Likewise.
* inet/getrpcbyname.c: Likewise.
* inet/getrpcbyname_r.c: Likewise.
* inet/getrpcbynumber.c: Likewise.
* inet/getrpcbynumber_r.c: Likewise.
* inet/getrpcent.c: Likewise.
* inet/getrpcent_r.c: Likewise.
* inet/getservent.c: Likewise.
* inet/getservent_r.c: Likewise.
* inet/getsrvbynm.c: Likewise.
* inet/getsrvbynm_r.c: Likewise.
* inet/getsrvbypt.c: Likewise.
* inet/getsrvbypt_r.c: Likewise.
* inet/herrno.c: Likewise.
* inet/netgroup.h: Likewise.
* ient/netinet/ether.h: Likewise.
* intl/bindtextdom.c: Likewise.
* intl/dcgettext.c: Likewise.
* intl/dgettext.c: Likewise.
* intl/gettext.c: Likewise.
* intl/gettext.h: Likewise.
* intl/gettextP.h: Likewise.
* intl/hash-string.h: Likewise.
* intl/loadmsgcat.c: Likewise.
* intl/localealias.c: Likewise.
* intl/textdomain.c: Likewise.
* io/creat.c: Likewise.
* io/getdirname.c: Likewise.
* io/lockf.c: Likewise.
* io/pwd.c: Likewise.
* io/test-utime.c: Likewise.
* locale/categories.def: Likewise.
* locale/codeset_name.c: Likewise.
* locale/lc-collate.c: Likewise.
* locale/lc-ctype.c: Likewise.
* locale/lc-messages.c: Likewise.
* locale/lc-monetary.c: Likewise.
* locale/lc-numeric.c: Likewise.
* locale/lc-time.c: Likewise.
* locale/loadlocale.c: Likewise.
* locale/localeconv.c: Likewise.
* locale/nl_langinfo.c: Likewise.
* locale/setlocale.c: Likewise.
* locale/strlen-hash.h: Likewise.
* locale/programs/charmap-kw.gperf: Likewise.
* locale/programs/charmap-kw.h: Likewise.
* locale/programs/charset.c: Likewise.
* locale/programs/ld-ctype.c: Likewise.
* locale/programs/ld-messages.c: Likewise.
* locale/programs/ld-monetary.c: Likewise.
* locale/programs/linereader.h: Likewise.
* locale/programs/locale-spec.c: Likewise.
* locale/programs/locales.h: Likewise.
* locale/programs/locfile-kw.gperf: Likewise.
* locale/programs/locfile-kw.h: Likewise.
* locale/programs/locfile-token.h: Likewise.
* locale/programs/simple-hash.h: Likewise.
* locale/programs/stringtrans.c: Likewise.
* locale/programs/stringtrans.h: Likewise.
* login/logout.c: Likewise.
* mach/bootprivport.c: Likewise.
* mach/devstream.c: Likewise.
* mach/hello.c: Likewise.
* mach/mach.h: Likewise.
* mach/mach_init.c: Likewise.
* mach/mach_init.h: Likewise.
* mach/mig-alloc.c: Likewise.
* mach/mig-dealloc.c: Likewise.
* mach/mutex-init.c: Likewise.
* mach/mutex-solid.c: Likewise.
* mach/setup-thread.c: Likewise.
* mach/spin-lock.h: Likewise.
* mach/spin-solid.c: Likewise.
* mach/mach/mig_support.h: Likewise.
* md5-crypt/md5-crypt.c: Likewise.
* misc/nlist.h: Likewise.
* nss/nss_files/files-ether.c: Likewise.
* posix/confstr.c: Likewise.
* posix/execl.c: Likewise.
* posix/execle.c: Likewise.
* posix/execlp.c: Likewise.
* posix/execv.c: Likewise.
* posix/execvp.c: Likewise.
* posix/fnmatch.c: Likewise.
* posix/getopt.c: Likewise.
* posix/getopt.h: Likewise.
* posix/getopt1.c: Likewise.
* posix/id.c: Likewise.
* posix/regex.c: Likewise.
* posix/setpgrp.c: Likewise.
* posix/unistd.h: Likewise.
* posix/wordexp.c: Likewise.
* pwd/fgetpwent.c: Likewise.
* pwd/getpwent.c: Likewise.
* pwd/getpwent_r.c: Likewise.
* pwd/getpwnam.c: Likewise.
* pwd/getpwnam_r.c: Likewise.
* pwd/getpwuid.c: Likewise.
* pwd/getpwuid_r.c: Likewise.
* pwd/putpwent.c: Likewise.
* resolv/gethnamaddr.c: Likewise.
* resolv/res_hconf.c: Likewise.
* resolv/res_hconf.h: Likewise.
* setjmp/longjmp.c: Likewise.
* setjmp/sigjmp.c: Likewise.
* setjmp/tst-setjmp.c: Likewise.
* stdio/clearerr.c: Likewise.
* stdio/ferror.c: Likewise.
* stdio/fgetc.c: Likewise.
* stdio/fgetpos.c: Likewise.
* stdio/fgets.c: Likewise.
* stdio/fileno.c: Likewise.
* stdio/fmemopen.c: Likewise.
* stdio/fopen.c: Likewise.
* stdio/fopncook.c: Likewise.
* stdio/fputc.c: Likewise.
* stdio/fputs.c: Likewise.
* stdio/fread.c: Likewise.
* stdio/freopen.c: Likewise.
* stdio/fseek.c: Likewise.
* stdio/fsetpos.c: Likewise.
* stdio/ftell.c: Likewise.
* stdio/fwrite.c: Likewise.
* stdio/getchar.c: Likewise.
* stdio/getdelim.c: Likewise.
* stdio/gets.c: Likewise.
* stdio/glue.c: Likewise.
* stdio/internals.c: Likewise.
* stdio/linewrap.c: Likewise.
* stdio/linewrap.h: Likewise.
* stdio/memstream.c: Likewise.
* stdio/newstream.c: Likewise.
* stdio/putchar.c: Likewise.
* stdio/puts.c: Likewise.
* stdio/rewind.c: Likewise.
* stdio/setbuf.c: Likewise.
* stdio/setbuffer.c: Likewise.
* stdio/setlinebuf.c: Likewise.
* stdio/setvbuf.c: Likewise.
* stdio/ungetc.c: Likewise.
* stdio/vasprintf.c: Likewise.
* stdio/vscanf.c: Likewise.
* stdio/vsnprintf.c: Likewise.
* stdio/vsprintf.c: Likewise.
* stdio/vsscanf.c: Likewise.
* stdio-common/asprintf.c: Likewise.
* stdio-common/dprintf.c: Likewise.
* stdio-common/errnobug.c: Likewise.
* stdio-common/fprintf.c: Likewise.
* stdio-common/getline.c: Likewise.
* stdio-common/getw.c: Likewise.
* stdio-common/perror.c: Likewise.
* stdio-common/psignal.c: Likewise.
* stdio-common/putw.c: Likewise.
* stdio-common/reg-printf.c: Likewise.
* stdio-common/scanf.c: Likewise.
* stdio-common/snprintf.c: Likewise.
* stdio-common/sprintf.c: Likewise.
* stdio-common/tempnam.c: Likewise.
* stdio-common/test_rdwr.c: Likewise.
* stdio-common/tst-fileno.c: Likewise.
* stdio-common/tst-printf.c: Likewise.
* stdio-common/tstgetln.c: Likewise.
* stdio-common/vprintf.c: Likewise.
* stdlib/drand48.c: Likewise.
* stdlib/drand48_r.c: Likewise.
* stdlib/erand48.c: Likewise.
* stdlib/erand48_r.c: Likewise.
* stdlib/exit.h: Likewise.
* stdlib/strtoq.c: Likewise.
* stdlib/strtoul.c: Likewise.
* stdlib/strtouq.c: Likewise.
* stdlib/test-canon.c: Likewise.
* stdlib/testdiv.c: Likewise.
* stdlib/testrand.c: Likewise.
* string/argz-append.c: Likewise.
* string/argz-count.c: Likewise.
* string/argz-create.c: Likewise.
* string/argz-ctsep.c: Likewise.
* string/argz-delete.c: Likewise.
* string/argz-extract.c: Likewise.
* string/argz-insert.c: Likewise.
* string/argz-next.c: Likewise.
* string/argz-stringify.c: Likewise.
* string/basename.c: Likewise.
* string/envz.c: Likewise.
* string/memfrob.c: Likewise.
* string/strcoll.c: Likewise.
* string/strdup.c: Likewise.
* string/string.h: Likewise.
* string/strndup.c: Likewise.
* string/strnlen.c: Likewise.
* string/strsignal.c: Likewise.
* string/strxfrm.c: Likewise.
* string/test-ffs.c: Likewise.
* string/testcopy.c: Likewise.
* sysdeps/generic/enbl-secure.c: Likewise.
* sysdeps/generic/memcopy.h: Likewise.
* sysdeps/generic/stpncpy.c: Likewise.
* sysdeps/generic/strcasecmp.c: Likewise.
* sysdeps/generic/strcat.c: Likewise.
* sysdeps/generic/strchr.c: Likewise.
* sysdeps/generic/strcpy.c: Likewise.
* sysdeps/generic/strcspn.c: Likewise.
* sysdeps/generic/strlen.c: Likewise.
* sysdeps/generic/strncase.c: Likewise.
* sysdeps/generic/strncat.c: Likewise.
* sysdeps/generic/strncpy.c: Likewise.
* sysdeps/generic/strpbrk.c: Likewise.
* sysdeps/generic/strsep.c: Likewise.
* sysdeps/generic/strspn.c: Likewise.
* sysdeps/generic/strstr.c: Likewise.
* sysdeps/generic/strtok.c: Likewise.
* sysdeps/generic/strtok_r.c: Likewise.
* sysdeps/mach/sleep.c: Likewise.
* sysdeps/posix/sleep.c: Likewise.
* sysdeps/stub/sleep.c: Likewise.
* time/date.c: Likewise.
* time/test_time.c: Likewise.
* wcsmbs/wmemcpy.c: Likewise.
* wctye/test_wctype.c: Likewise.
* wctye/towctrans.c: Likewise.
* wctye/wcfuncs.c: Likewise.
* wctye/wctrans.c: Likewise.
1997-02-13 22:15 Miles Bader <miles@gnu.ai.mit.edu>
* argp/Makefile: New file.
* argp/argp.h: Likewise.
* argp/argp-ba.c: Likewise.
* argp/argp-fmtstream.c: Likewise.
* argp/argp-fmtstream.h: Likewise.
* argp/argp-fs-xinl.c: Likewise.
* argp/argp-help.c: Likewise.
* argp/argp-namefrob.h: Likewise.
* argp/argp-parse.c: Likewise.
* argp/argp-pv.c: Likewise.
* argp/argp-pvh.c: Likewise.
* argp/argp-test.c: Likewise.
* argp/argp-xinl.c: Likewise.
* libio/_G_config.h: Make sure wint_t is also defined for old gcc
1997-02-09 04:35 Ulrich Drepper <drepper@cygnus.com>
* stdio-common/_itoa.h: Update copyright.
Diffstat (limited to 'argp/argp-parse.c')
-rw-r--r-- | argp/argp-parse.c | 850 |
1 files changed, 850 insertions, 0 deletions
diff --git a/argp/argp-parse.c b/argp/argp-parse.c new file mode 100644 index 0000000000..f1f4ce9dfc --- /dev/null +++ b/argp/argp-parse.c @@ -0,0 +1,850 @@ +/* Hierarchial argument parsing, layered over getopt + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <getopt.h> + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include <libintl.h> +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +# define gettext(msgid) (msgid) +#endif +#endif + +#if _LIBC - 0 +#include <libc-lock.h> +#else +#ifdef HAVE_CTHREADS_H +#include <cthreads.h> +#endif +#endif /* _LIBC */ + +#include "argp.h" +#include "argp-namefrob.h" + +/* Getopt return values. */ +#define KEY_END (-1) /* The end of the options. */ +#define KEY_ARG 1 /* A non-option argument. */ +#define KEY_ERR '?' /* An error parsing the options. */ + +/* The meta-argument used to prevent any further arguments being interpreted + as options. */ +#define QUOTE "--" + +/* The number of bits we steal in a long-option value for our own use. */ +#define GROUP_BITS CHAR_BIT + +/* The number of bits available for the user value. */ +#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) +#define USER_MASK ((1 << USER_BITS) - 1) + +/* EZ alias for ARGP_ERR_UNKNOWN. */ +#define EBADKEY ARGP_ERR_UNKNOWN + +/* Default options. */ + +/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep + for one second intervals, decrementing _ARGP_HANG until it's zero. Thus + you can force the program to continue by attaching a debugger and setting + it to 0 yourself. */ +volatile int _argp_hang = 0; + +#define OPT_PROGNAME -2 +#define OPT_USAGE -3 +#define OPT_HANG -4 + +static const struct argp_option argp_default_options[] = +{ + {"help", '?', 0, 0, "Give this help list", -1}, + {"usage", OPT_USAGE, 0, 0, "Give a short usage message"}, + {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, "Set the program name"}, + {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + "Hang for SECS seconds (default 3600)"}, + {0, 0} +}; + +static error_t +argp_default_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case '?': + __argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + case OPT_USAGE: + __argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case OPT_PROGNAME: /* Set the program name. */ + program_invocation_name = arg; + + /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka + __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined + to be that, so we have to be a bit careful here.] */ + arg = strrchr (arg, '/'); + if (arg) + program_invocation_short_name = arg + 1; + else + program_invocation_short_name = program_invocation_name; + + if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) + == ARGP_PARSE_ARGV0) + state->argv[0] = program_invocation_name; /* Update what getopt uses too. */ + + break; + + case OPT_HANG: + _argp_hang = atoi (arg ? arg : "3600"); + while (_argp_hang-- > 0) + __sleep (1); + break; + + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_default_argp = + {argp_default_options, &argp_default_parser}; + + +static const struct argp_option argp_version_options[] = +{ + {"version", 'V', 0, 0, "Print program version", -1}, + {0, 0} +}; + +static error_t +argp_version_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'V': + if (argp_program_version_hook) + (*argp_program_version_hook) (state->out_stream, state); + else if (argp_program_version) + fprintf (state->out_stream, "%s\n", argp_program_version); + else + __argp_error (state, _("No version known!?")); + if (! (state->flags & ARGP_NO_EXIT)) + exit (0); + break; + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_version_argp = + {argp_version_options, &argp_version_parser}; + +/* Returns the offset into the getopt long options array LONG_OPTIONS of a + long option with called NAME, or -1 if none is found. Passing NULL as + NAME will return the number of options. */ +static int +find_long_option (struct option *long_options, const char *name) +{ + struct option *l = long_options; + while (l->name != NULL) + if (name != NULL && strcmp (l->name, name) == 0) + return l - long_options; + else + l++; + if (name == NULL) + return l - long_options; + else + return -1; +} + +/* If we can, we regulate access to getopt, which is non-reentrant, with a + mutex. Since the case we're trying to guard against is two different + threads interfering, and it's possible that someone might want to call + argp_parse recursively (they're careful), we use a recursive lock if + possible. */ + +#if _LIBC - 0 + +__libc_lock_define_initialized_recursive (static, getopt_lock) +#define LOCK_GETOPT __libc_lock_lock_recursive (getopt_lock) +#define UNLOCK_GETOPT __libc_lock_unlock_recursive (getopt_lock) + +#else /* !_LIBC */ +#ifdef HAVE_CTHREADS_H + +static struct mutex getopt_lock = MUTEX_INITIALIZER; +#define LOCK_GETOPT mutex_lock (&getopt_lock) +#define UNLOCK_GETOPT mutex_unlock (&getopt_lock) + +#else /* !HAVE_CTHREADS_H */ + +#define LOCK_GETOPT (void)0 +#define UNLOCK_GETOPT (void)0 + +#endif /* HAVE_CTHREADS_H */ +#endif /* _LIBC */ + +/* This hack to allow programs that know what's going on to call argp + recursively. If someday argp is changed not to use the non-reentrant + getopt interface, we can get rid of this shit. XXX */ +void +_argp_unlock_xxx (void) +{ + UNLOCK_GETOPT; +} + +/* The state of a `group' during parsing. Each group corresponds to a + particular argp structure from the tree of such descending from the top + level argp passed to argp_parse. */ +struct group +{ + /* This group's parsing function. */ + argp_parser_t parser; + + /* Points to the point in SHORT_OPTS corresponding to the end of the short + options for this group. We use it to determine from which group a + particular short options is from. */ + char *short_end; + + /* The number of non-option args sucessfully handled by this parser. */ + unsigned args_processed; + + /* This group's parser's parent's group. */ + struct group *parent; + unsigned parent_index; /* And the our position in the parent. */ + + /* These fields are swapped into and out of the state structure when + calling this group's parser. */ + void *input, **child_inputs; + void *hook; +}; + +/* Call GROUP's parser with KEY and ARG, swapping any group-specific info + from STATE before calling, and back into state afterwards. If GROUP has + no parser, EBADKEY is returned. */ +static error_t +group_parse (struct group *group, struct argp_state *state, int key, char *arg) +{ + if (group->parser) + { + error_t err; + state->hook = group->hook; + state->input = group->input; + state->child_inputs = group->child_inputs; + state->arg_num = group->args_processed; + err = (*group->parser)(key, arg, state); + group->hook = state->hook; + return err; + } + else + return EBADKEY; +} + +struct parser +{ + const struct argp *argp; + + /* SHORT_OPTS is the getopt short options string for the union of all the + groups of options. */ + char *short_opts; + /* LONG_OPTS is the array of getop long option structures for the union of + all the groups of options. */ + struct option *long_opts; + + /* States of the various parsing groups. */ + struct group *groups; + /* The end of the GROUPS array. */ + struct group *egroup; + /* An vector containing storage for the CHILD_INPUTS field in all groups. */ + void **child_inputs; + + /* True if we think using getopt is still useful; if false, then + remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is + cleared whenever getopt returns KEY_END, but may be set again if the user + moves the next argument pointer backwards. */ + int try_getopt; + + /* State block supplied to parsing routines. */ + struct argp_state state; + + /* Memory used by this parser. */ + void *storage; +}; + +/* The next usable entries in the various parser tables being filled in by + convert_options. */ +struct parser_convert_state +{ + struct parser *parser; + char *short_end; + struct option *long_end; + void **child_inputs_end; +}; + +/* Converts all options in ARGP (which is put in GROUP) and ancestors + into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and + CVT->LONG_END are the points at which new options are added. Returns the + next unused group entry. CVT holds state used during the conversion. */ +static struct group * +convert_options (const struct argp *argp, + struct group *parent, unsigned parent_index, + struct group *group, struct parser_convert_state *cvt) +{ + /* REAL is the most recent non-alias value of OPT. */ + const struct argp_option *real = argp->options; + const struct argp_child *children = argp->children; + + if (real || argp->parser) + { + const struct argp_option *opt; + + if (real) + for (opt = real; !__option_is_end (opt); opt++) + { + if (! (opt->flags & OPTION_ALIAS)) + /* OPT isn't an alias, so we can use values from it. */ + real = opt; + + if (! (real->flags & OPTION_DOC)) + /* A real option (not just documentation). */ + { + if (__option_is_short (opt)) + /* OPT can be used as a short option. */ + { + *cvt->short_end++ = opt->key; + if (real->arg) + { + *cvt->short_end++ = ':'; + if (real->flags & OPTION_ARG_OPTIONAL) + *cvt->short_end++ = ':'; + } + *cvt->short_end = '\0'; /* keep 0 terminated */ + } + + if (opt->name + && find_long_option (cvt->parser->long_opts, opt->name) < 0) + /* OPT can be used as a long option. */ + { + cvt->long_end->name = opt->name; + cvt->long_end->has_arg = + (real->arg + ? (real->flags & OPTION_ARG_OPTIONAL + ? optional_argument + : required_argument) + : no_argument); + cvt->long_end->flag = 0; + /* we add a disambiguating code to all the user's + values (which is removed before we actually call + the function to parse the value); this means that + the user loses use of the high 8 bits in all his + values (the sign of the lower bits is preserved + however)... */ + cvt->long_end->val = + ((opt->key | real->key) & USER_MASK) + + (((group - cvt->parser->groups) + 1) << USER_BITS); + + /* Keep the LONG_OPTS list terminated. */ + (++cvt->long_end)->name = NULL; + } + } + } + + group->parser = argp->parser; + group->short_end = cvt->short_end; + group->args_processed = 0; + group->parent = parent; + group->parent_index = parent_index; + group->input = 0; + group->hook = 0; + group->child_inputs = 0; + + if (children) + /* Assign GROUP's CHILD_INPUTS field some space from + CVT->child_inputs_end.*/ + { + unsigned num_children = 0; + while (children[num_children].argp) + num_children++; + group->child_inputs = cvt->child_inputs_end; + cvt->child_inputs_end += num_children; + } + + parent = group++; + } + else + parent = 0; + + if (children) + { + unsigned index = 0; + while (children->argp) + group = + convert_options (children++->argp, parent, index++, group, cvt); + } + + return group; +} + +/* Find the merged set of getopt options, with keys appropiately prefixed. */ +static void +parser_convert (struct parser *parser, const struct argp *argp, int flags) +{ + struct parser_convert_state cvt; + + cvt.parser = parser; + cvt.short_end = parser->short_opts; + cvt.long_end = parser->long_opts; + cvt.child_inputs_end = parser->child_inputs; + + if (flags & ARGP_IN_ORDER) + *cvt.short_end++ = '-'; + else if (flags & ARGP_NO_ARGS) + *cvt.short_end++ = '+'; + *cvt.short_end = '\0'; + + cvt.long_end->name = NULL; + + parser->argp = argp; + + if (argp) + parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); + else + parser->egroup = parser->groups; /* No parsers at all! */ +} + +/* Lengths of various parser fields which we will allocated. */ +struct parser_sizes +{ + size_t short_len; /* Getopt short options string. */ + size_t long_len; /* Getopt long options vector. */ + size_t num_groups; /* Group structures we allocate. */ + size_t num_child_inputs; /* Child input slots. */ +}; + +/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of + argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by + the maximum lengths of the resulting merged getopt short options string and + long-options array, respectively. */ +static void +calc_sizes (const struct argp *argp, struct parser_sizes *szs) +{ + const struct argp_child *child = argp->children; + const struct argp_option *opt = argp->options; + + if (opt || argp->parser) + { + szs->num_groups++; + if (opt) + { + int num_opts = 0; + while (!__option_is_end (opt++)) + num_opts++; + szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */ + szs->long_len += num_opts; + } + } + + if (child) + while (child->argp) + { + calc_sizes ((child++)->argp, szs); + szs->num_child_inputs++; + } +} + +/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */ +static error_t +parser_init (struct parser *parser, const struct argp *argp, + int argc, char **argv, int flags, void *input) +{ + error_t err = 0; + struct group *group; + struct parser_sizes szs; + + szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; + szs.long_len = 0; + szs.num_groups = 0; + szs.num_child_inputs = 0; + + if (argp) + calc_sizes (argp, &szs); + + /* Lengths of the various bits of storage used by PARSER. */ +#define GLEN (szs.num_groups + 1) * sizeof (struct group) +#define CLEN (szs.num_child_inputs * sizeof (void *)) +#define LLEN ((szs.long_len + 1) * sizeof (struct option)) +#define SLEN (szs.short_len + 1) + + parser->storage = malloc (GLEN + CLEN + LLEN + SLEN); + if (! parser->storage) + return ENOMEM; + + parser->groups = parser->storage; + parser->child_inputs = parser->storage + GLEN; + parser->long_opts = parser->storage + GLEN + CLEN; + parser->short_opts = parser->storage + GLEN + CLEN + LLEN; + + memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); + parser_convert (parser, argp, flags); + + parser->try_getopt = 1; + + memset (&parser->state, 0, sizeof (struct argp_state)); + parser->state.argp = parser->argp; + parser->state.argc = argc; + parser->state.argv = argv; + parser->state.err_stream = stderr; + parser->state.out_stream = stdout; + parser->state.next = 0; /* Tell getopt to initialize. */ + + /* Call each parser for the first time, giving it a chance to propagate + values to child parsers. */ + if (parser->groups < parser->egroup) + parser->groups->input = input; + for (group = parser->groups; + group < parser->egroup && (!err || err == EBADKEY); + group++) + { + if (group->parent) + /* If a child parser, get the initial input value from the parent. */ + group->input = group->parent->child_inputs[group->parent_index]; + err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0); + } + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + if (err) + return err; + + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + parser->state.name = argv[0]; + else + parser->state.name = program_invocation_name; + + /* Getopt is (currently) non-reentrant. */ + LOCK_GETOPT; + + if (parser->state.flags & ARGP_NO_ERRS) + { + opterr = 0; + if (parser->state.flags & ARGP_PARSE_ARGV0) + /* getopt always skips ARGV[0], so we have to fake it out. As long + as OPTERR is 0, then it shouldn't actually try to access it. */ + parser->state.argv--, parser->state.argc++; + } + else + opterr = 1; /* Print error messages. */ + + return 0; +} + +/* Free any storage consumed by PARSER (but not PARSER itself). */ +static error_t +parser_finalize (struct parser *parser, + error_t err, int arg_ebadkey, int *end_index) +{ + struct group *group; + + UNLOCK_GETOPT; + + if (err == EBADKEY && arg_ebadkey) + /* Suppress errors generated by unparsed arguments. */ + err = 0; + + if (! err) + if (parser->state.next == parser->state.argc) + /* We successfully parsed all arguments! Call all the parsers again, + just a few more times... */ + { + for (group = parser->groups; + group < parser->egroup && (!err || err==EBADKEY); + group++) + if (group->args_processed == 0) + err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0); + for (group = parser->groups; + group < parser->egroup && (!err || err==EBADKEY); + group++) + err = group_parse (group, &parser->state, ARGP_KEY_END, 0); + + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + } + else if (end_index) + /* Return any remaining arguments to the user. */ + *end_index = parser->state.next; + else + /* No way to return the remaining arguments, they must be bogus. */ + { + if (!(parser->state.flags & ARGP_NO_ERRS) && parser->state.err_stream) + fprintf (parser->state.err_stream, + _("%s: Too many arguments\n"), parser->state.name); + err = EBADKEY; + } + + /* Okay, we're all done, with either an error or success. We only call the + parsers once more, to indicate which one. */ + + if (err) + { + /* Maybe print an error message. */ + if (err == EBADKEY) + /* An appropriate message describing what the error was should have + been printed earlier. */ + __argp_state_help (&parser->state, parser->state.err_stream, + ARGP_HELP_STD_ERR); + + /* Since we didn't exit, give each parser an error indication. */ + for (group = parser->groups; group < parser->egroup; group++) + group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); + } + else + /* Do final cleanup, including propagating back values from parsers. */ + { + /* We pass over the groups in reverse order so that child groups are + given a chance to do there processing before passing back a value to + the parent. */ + for (group = parser->egroup - 1 + ; group >= parser->groups && (!err || err == EBADKEY) + ; group--) + err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0); + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + } + + if (err == EBADKEY) + err = EINVAL; + + free (parser->storage); + + return err; +} + +/* Call the user parsers to parse the non-option argument VAL, at the current + position, returning any error. */ +static error_t +parser_parse_arg (struct parser *parser, char *val) +{ + int index = parser->state.next; + error_t err = EBADKEY; + struct group *group; + + for (group = parser->groups + ; group < parser->egroup && err == EBADKEY + ; group++) + err = group_parse (group, &parser->state, ARGP_KEY_ARG, val); + + if (!err) + if (parser->state.next >= index) + /* Remember that we successfully processed a non-option + argument -- but only if the user hasn't gotten tricky and set + the clock back. */ + (--group)->args_processed++; + else + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; + + return err; +} + +/* Call the user parsers to parse the option OPT, with argument VAL, at the + current position, returning any error. */ +static error_t +parser_parse_opt (struct parser *parser, int opt, char *val) +{ + /* The group key encoded in the high bits; 0 for short opts or + group_number + 1 for long opts. */ + int group_key = opt >> USER_BITS; + + if (group_key == 0) + /* A short option. By comparing OPT's position in SHORT_OPTS to the + various starting positions in each group's SHORT_END field, we can + determine which group OPT came from. */ + { + struct group *group; + char *short_index = strchr (parser->short_opts, opt); + + if (short_index) + for (group = parser->groups; group < parser->egroup; group++) + if (group->short_end > short_index) + return group_parse (group, &parser->state, opt, optarg); + + return EBADKEY; /* until otherwise asserted */ + } + else + /* A long option. We use shifts instead of masking for extracting + the user value in order to preserve the sign. */ + return + group_parse (&parser->groups[group_key - 1], &parser->state, + (opt << GROUP_BITS) >> GROUP_BITS, optarg); +} + +/* Parse the next argument in PARSER (as indicated by PARSER->state.next). + Any error from the parsers is returned, and *ARGP_EBADKEY indicates + whether a value of EBADKEY is due to an unrecognized argument (which is + generally not fatal). */ +static error_t +parser_parse_next (struct parser *parser, int *arg_ebadkey) +{ + int opt; + error_t err = 0; + + if (parser->state.quoted && parser->state.next < parser->state.quoted) + /* The next argument pointer has been moved to before the quoted + region, so pretend we never saw the quoting `--', and give getopt + another chance. If the user hasn't removed it, getopt will just + process it again. */ + parser->state.quoted = 0; + + if (parser->try_getopt && !parser->state.quoted) + /* Give getopt a chance to parse this. */ + { + optind = parser->state.next; /* Put it back in OPTIND for getopt. */ + optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */ + if (parser->state.flags & ARGP_LONG_ONLY) + opt = getopt_long_only (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + else + opt = getopt_long (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + parser->state.next = optind; /* And see what getopt did. */ + + if (opt == KEY_END) + /* Getopt says there are no more options, so stop using + getopt; we'll continue if necessary on our own. */ + { + parser->try_getopt = 0; + if (parser->state.next > 1 + && strcmp (parser->state.argv[parser->state.next - 1], QUOTE) + == 0) + /* Not only is this the end of the options, but it's a + `quoted' region, which may have args that *look* like + options, so we definitely shouldn't try to use getopt past + here, whatever happens. */ + parser->state.quoted = parser->state.next; + } + else if (opt == KEY_ERR && optopt != KEY_END) + /* KEY_ERR can have the same value as a valid user short + option, but in the case of a real error, getopt sets OPTOPT + to the offending character, which can never be KEY_END. */ + { + *arg_ebadkey = 0; + return EBADKEY; + } + } + else + opt = KEY_END; + + if (opt == KEY_END) + /* We're past what getopt considers the options. */ + if (parser->state.next >= parser->state.argc + || (parser->state.flags & ARGP_NO_ARGS)) + /* Indicate that we're done. */ + { + *arg_ebadkey = 1; + return EBADKEY; + } + else + /* A non-option arg. */ + err = + parser_parse_arg (parser, parser->state.argv[parser->state.next++]); + else if (opt == KEY_ARG) + /* A non-option argument; try each parser in turn. */ + err = parser_parse_arg (parser, optarg); + else + err = parser_parse_opt (parser, opt, optarg); + + if (err == EBADKEY) + { + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); + parser->state.next--; /* Put back the unused argument. */ + } + + return err; +} + +/* Parse the options strings in ARGC & ARGV according to the argp in ARGP. + FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, EINVAL is returned; if some parser routine + returned a non-zero value, it is returned; otherwise 0 is returned. */ +error_t +__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, + int *end_index, void *input) +{ + error_t err; + struct parser parser; + + /* If true, then err == EBADKEY is a result of a non-option argument failing + to be parsed (which in some cases isn't actually an error). */ + int arg_ebadkey = 0; + + if (! (flags & ARGP_NO_HELP)) + /* Add our own options. */ + { + struct argp_child *child = alloca (4 * sizeof (struct argp_child)); + struct argp *top_argp = alloca (sizeof (struct argp)); + + /* TOP_ARGP has no options, it just serves to group the user & default + argps. */ + memset (top_argp, 0, sizeof (*top_argp)); + top_argp->children = child; + + memset (child, 0, 4 * sizeof (struct argp_child)); + + if (argp) + (child++)->argp = argp; + (child++)->argp = &argp_default_argp; + if (argp_program_version || argp_program_version_hook) + (child++)->argp = &argp_version_argp; + child->argp = 0; + + argp = top_argp; + } + + /* Construct a parser for these arguments. */ + err = parser_init (&parser, argp, argc, argv, flags, input); + + if (! err) + /* Parse! */ + { + while (! err) + err = parser_parse_next (&parser, &arg_ebadkey); + err = parser_finalize (&parser, err, arg_ebadkey, end_index); + } + + return err; +} +#ifdef weak_alias +weak_alias (__argp_parse, argp_parse) +#endif |