diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:17 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:17 -0800 |
commit | cea198a11f15a2eb071d98491ca9a8bc8cebfbc4 (patch) | |
tree | bbb428d958c5d908c53239a56a30f72a519b8471 /lib | |
parent | 5a23b9fcc3a82c4580e115cb4835d796b7995d0c (diff) | |
download | bison-donut-release.tar.gz |
auto import from //depot/cupcake/@135843android-sdk-tools_r2android-sdk-1.6_r2android-sdk-1.6_r1android-sdk-1.6-docs_r1android-sdk-1.5_r3android-sdk-1.5_r1android-sdk-1.5-preandroid-1.6_r2android-1.6_r1.5android-1.6_r1.4android-1.6_r1.3android-1.6_r1.2android-1.6_r1.1android-1.6_r1android-1.5r4android-1.5r3android-1.5r2android-1.5donut-release2donut-releasedonutcupcake-releasecupcake
Diffstat (limited to 'lib')
89 files changed, 18078 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 00000000..25490d39 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,623 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# lib/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +srcdir = . +top_srcdir = .. + +pkgdatadir = $(datadir)/bison +pkglibdir = $(libdir)/bison +pkgincludedir = $(includedir)/bison +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = /usr/bin/install -c +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-unknown-linux-gnu +host_triplet = x86_64-unknown-linux-gnu +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gnulib.mk dirname.c dirname.h dup-safer.c error.c \ + error.h exitfail.c exitfail.h fd-safer.c fopen-safer.c \ + getopt.c getopt1.c hard-locale.c hard-locale.h hash.c hash.h \ + malloc.c obstack.c obstack.h pipe-safer.c quote.c quote.h \ + quotearg.c quotearg.h stdio--.h stdio-safer.h stpcpy.c \ + strdup.c strdup.h strerror.c strndup.c strndup.h strnlen.c \ + strnlen.h strtol.c strtoul.c strverscmp.c strverscmp.h \ + unistd--.h unistd-safer.h unlocked-io.h xalloc.h xmalloc.c +subdir = lib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/bison-i18n.m4 \ + $(top_srcdir)/m4/c-working.m4 $(top_srcdir)/m4/cxx.m4 \ + $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dmalloc.m4 \ + $(top_srcdir)/m4/dos.m4 $(top_srcdir)/m4/error.m4 \ + $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \ + $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/gettext_gl.m4 \ + $(top_srcdir)/m4/gnulib.m4 $(top_srcdir)/m4/hard-locale.m4 \ + $(top_srcdir)/m4/hash.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/inttypes_h_gl.m4 \ + $(top_srcdir)/m4/lib-ld_gl.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix_gl.m4 $(top_srcdir)/m4/m4.m4 \ + $(top_srcdir)/m4/mbrtowc.m4 $(top_srcdir)/m4/mbstate_t.m4 \ + $(top_srcdir)/m4/mbswidth.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/obstack.m4 $(top_srcdir)/m4/onceonly.m4 \ + $(top_srcdir)/m4/po_gl.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \ + $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint_h_gl.m4 \ + $(top_srcdir)/m4/stdio-safer.m4 $(top_srcdir)/m4/stpcpy.m4 \ + $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \ + $(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/strnlen.m4 \ + $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \ + $(top_srcdir)/m4/strverscmp.m4 $(top_srcdir)/m4/subpipe.m4 \ + $(top_srcdir)/m4/timevar.m4 $(top_srcdir)/m4/uintmax_t_gl.m4 \ + $(top_srcdir)/m4/ulonglong_gl.m4 \ + $(top_srcdir)/m4/unistd-safer.m4 $(top_srcdir)/m4/unistd_h.m4 \ + $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/warning.m4 \ + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xstrndup.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLIBRARIES_INSTALL = $(INSTALL_DATA) +LIBRARIES = $(lib_LIBRARIES) $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libbison_a_AR = $(AR) $(ARFLAGS) +am__DEPENDENCIES_1 = dirname$U.o exitfail$U.o hard-locale$U.o hash$U.o quote$U.o quotearg$U.o fopen-safer$U.o dup-safer$U.o fd-safer$U.o pipe-safer$U.o xmalloc$U.o +am__objects_1 = abitset.$(OBJEXT) bitset.$(OBJEXT) \ + bitset_stats.$(OBJEXT) bitsetv.$(OBJEXT) ebitset.$(OBJEXT) \ + lbitset.$(OBJEXT) vbitset.$(OBJEXT) +am__objects_2 = bitsetv-print.$(OBJEXT) +am__objects_3 = timevar.$(OBJEXT) +am__objects_4 = get-errno.$(OBJEXT) subpipe.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) argmatch.$(OBJEXT) \ + basename.$(OBJEXT) stripslash.$(OBJEXT) mbswidth.$(OBJEXT) \ + xalloc-die.$(OBJEXT) xstrndup.$(OBJEXT) +am_libbison_a_OBJECTS = $(am__objects_4) +libbison_a_OBJECTS = $(am_libbison_a_OBJECTS) +liby_a_AR = $(AR) $(ARFLAGS) +liby_a_LIBADD = +am_liby_a_OBJECTS = main.$(OBJEXT) yyerror.$(OBJEXT) +liby_a_OBJECTS = $(am_liby_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libbison_a_SOURCES) $(liby_a_SOURCES) +DIST_SOURCES = $(libbison_a_SOURCES) $(liby_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run aclocal-1.9 +AMDEP_FALSE = # +AMDEP_TRUE = +AMTAR = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run tar +AUTOCONF = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run autoconf +AUTOHEADER = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run autoheader +AUTOM4TE = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run autom4te +AUTOMAKE = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run automake-1.9 +AWK = gawk +BISON_CXX_WORKS = : +BISON_CXX_WORKS_FALSE = # +BISON_CXX_WORKS_TRUE = +BISON_LOCALEDIR = /usr/share/locale +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CPP = gcc -E +CPPFLAGS = +CXX = g++ +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = grep -E +EXEEXT = +GCC = yes +GETOPT_H = +GMSGFMT = /usr/bin/msgfmt +HAVE__BOOL = 1 +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +INTLLIBS = +INTL_MACOSX_LIBS = +LDFLAGS = +LEX = flex +LEXLIB = -lfl +LEX_OUTPUT_ROOT = lex.yy +LIBICONV = -liconv +LIBINTL = +LIBOBJS = dirname$U.o exitfail$U.o hard-locale$U.o hash$U.o quote$U.o quotearg$U.o fopen-safer$U.o dup-safer$U.o fd-safer$U.o pipe-safer$U.o xmalloc$U.o +LIBS = +LTLIBICONV = -liconv +LTLIBINTL = +LTLIBOBJS = dirname$U.lo exitfail$U.lo hard-locale$U.lo hash$U.lo quote$U.lo quotearg$U.lo fopen-safer$U.lo dup-safer$U.lo fd-safer$U.lo pipe-safer$U.lo xmalloc$U.lo +M4 = /usr/bin/m4 +MAKEINFO = ${SHELL} /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/missing --run makeinfo +MKINSTALLDIRS = $(top_builddir)/build-aux/mkinstalldirs +MSGFMT = /usr/bin/msgfmt +MSGMERGE = /usr/bin/msgmerge +O0CFLAGS = -g +O0CXXFLAGS = -g +OBJEXT = o +PACKAGE = bison +PACKAGE_BUGREPORT = bug-bison@gnu.org +PACKAGE_NAME = GNU Bison +PACKAGE_STRING = GNU Bison 2.3 +PACKAGE_TARNAME = bison +PACKAGE_VERSION = 2.3 +PATH_SEPARATOR = : +POSUB = po +RANLIB = ranlib +SET_MAKE = +SHELL = /bin/sh +STDBOOL_H = +STRIP = +UNISTD_H = +USE_NLS = yes +VALGRIND = +VERSION = 2.3 +WARNING_CFLAGS = +WARNING_CXXFLAGS = +WERROR_CFLAGS = +XGETTEXT = /usr/bin/xgettext +YACC = bison -y +YACC_LIBRARY = liby.a +YACC_SCRIPT = yacc +ac_ct_CC = gcc +ac_ct_CXX = g++ +ac_ct_RANLIB = ranlib +ac_ct_STRIP = +aclocaldir = ${datadir}/aclocal +am__fastdepCC_FALSE = # +am__fastdepCC_TRUE = +am__fastdepCXX_FALSE = # +am__fastdepCXX_TRUE = +am__include = include +am__leading_dot = . +am__quote = +am__tar = ${AMTAR} chof - "$$tardir" +am__untar = ${AMTAR} xf - +bindir = ${exec_prefix}/bin +build = x86_64-unknown-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = unknown +datadir = ${prefix}/share +exec_prefix = ${prefix} +host = x86_64-unknown-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = unknown +includedir = ${prefix}/include +infodir = ${prefix}/info +install_sh = /usr/local/google/workspace/WebKit/tools/bison-2.3/build-aux/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localstatedir = ${prefix}/var +mandir = ${prefix}/man +mkdir_p = mkdir -p -- +oldincludedir = /usr/include +prefix = /home/phanna/src/bison +program_transform_name = s,x,x, +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +sysconfdir = ${prefix}/etc +target_alias = +AM_CFLAGS = $(WARNING_CFLAGS) +BUILT_SOURCES = $(GETOPT_H) $(STDBOOL_H) $(UNISTD_H) +EXTRA_DIST = getopt_.h getopt_int.h stdbool_.h +MOSTLYCLEANFILES = getopt.h getopt.h-t stdbool.h stdbool.h-t unistd.h +lib_LIBRARIES = $(YACC_LIBRARY) +EXTRA_LIBRARIES = liby.a +noinst_LIBRARIES = libbison.a +liby_a_SOURCES = main.c yyerror.c +libbison_a_SOURCES = $(lib_SOURCES) + +# This file is generated automatically by "bootstrap". + +# This is for those projects which use "gettextize --intl" to put a source-code +# copy of libintl into their package. In such projects, every Makefile.am needs +# -I$(top_builddir)/intl, so that <libintl.h> can be found in this directory. +# For the Makefile.ams in other directories it is the maintainer's +# responsibility; for the one from gnulib we do it here. +# This option has no effect when the user disables NLS (because then the intl +# directory contains no libintl.h file) or when the project does not use +# "gettextize --intl". +# (commented out by bootstrap) AM_CPPFLAGS += -I$(top_builddir)/intl +lib_SOURCES = get-errno.h get-errno.c subpipe.h subpipe.c \ + $(bitsets_sources) $(additional_bitsets_sources) \ + $(timevars_sources) argmatch.h argmatch.c basename.c \ + stripslash.c exit.h gettext.h mbswidth.h mbswidth.c stpcpy.h \ + verify.h xalloc-die.c xstrndup.h xstrndup.c + +# Implementation of bitsets +bitsets_sources = \ + abitset.c abitset.h bbitset.h bitset.c bitset.h bitset_stats.c \ + bitset_stats.h bitsetv.c bitsetv.h ebitset.c ebitset.h lbitset.c \ + lbitset.h libiberty.h vbitset.c vbitset.h + + +# Additional bitset operations. +additional_bitsets_sources = \ + bitsetv-print.h bitsetv-print.c + + +# timevars, stolen from GCC. +timevars_sources = \ + timevar.h timevar.c timevar.def + +libbison_a_LIBADD = $(LIBOBJS) $(ALLOCA) +libbison_a_DEPENDENCIES = $(libbison_a_LIBADD) +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/gnulib.mk $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + p=$(am__strip_dir) \ + echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ + $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbison.a: $(libbison_a_OBJECTS) $(libbison_a_DEPENDENCIES) + -rm -f libbison.a + $(libbison_a_AR) libbison.a $(libbison_a_OBJECTS) $(libbison_a_LIBADD) + $(RANLIB) libbison.a +liby.a: $(liby_a_OBJECTS) $(liby_a_DEPENDENCIES) + -rm -f liby.a + $(liby_a_AR) liby.a $(liby_a_OBJECTS) $(liby_a_LIBADD) + $(RANLIB) liby.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include $(DEPDIR)/dirname.Po +include $(DEPDIR)/dup-safer.Po +include $(DEPDIR)/error.Po +include $(DEPDIR)/exitfail.Po +include $(DEPDIR)/fd-safer.Po +include $(DEPDIR)/fopen-safer.Po +include $(DEPDIR)/getopt.Po +include $(DEPDIR)/getopt1.Po +include $(DEPDIR)/hard-locale.Po +include $(DEPDIR)/hash.Po +include $(DEPDIR)/malloc.Po +include $(DEPDIR)/obstack.Po +include $(DEPDIR)/pipe-safer.Po +include $(DEPDIR)/quote.Po +include $(DEPDIR)/quotearg.Po +include $(DEPDIR)/stpcpy.Po +include $(DEPDIR)/strdup.Po +include $(DEPDIR)/strerror.Po +include $(DEPDIR)/strndup.Po +include $(DEPDIR)/strnlen.Po +include $(DEPDIR)/strtol.Po +include $(DEPDIR)/strtoul.Po +include $(DEPDIR)/strverscmp.Po +include $(DEPDIR)/xmalloc.Po +include ./$(DEPDIR)/abitset.Po +include ./$(DEPDIR)/argmatch.Po +include ./$(DEPDIR)/basename.Po +include ./$(DEPDIR)/bitset.Po +include ./$(DEPDIR)/bitset_stats.Po +include ./$(DEPDIR)/bitsetv-print.Po +include ./$(DEPDIR)/bitsetv.Po +include ./$(DEPDIR)/ebitset.Po +include ./$(DEPDIR)/get-errno.Po +include ./$(DEPDIR)/lbitset.Po +include ./$(DEPDIR)/main.Po +include ./$(DEPDIR)/mbswidth.Po +include ./$(DEPDIR)/stripslash.Po +include ./$(DEPDIR)/subpipe.Po +include ./$(DEPDIR)/timevar.Po +include ./$(DEPDIR)/vbitset.Po +include ./$(DEPDIR)/xalloc-die.Po +include ./$(DEPDIR)/xstrndup.Po +include ./$(DEPDIR)/yyerror.Po + +.c.o: + if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ + then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +# source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(COMPILE) -c $< + +.c.obj: + if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ + then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +# source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libLIBRARIES clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLIBRARIES clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-libLIBRARIES install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLIBRARIES + + +# We need the following in order to create <getopt.h> when the system +# doesn't have one that works with the given compiler. +getopt.h: getopt_.h + cp $(srcdir)/getopt_.h $@-t + mv $@-t $@ + +# We need the following in order to create <stdbool.h> when the system +# doesn't have one that works. +stdbool.h: stdbool_.h + sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h > $@-t + mv $@-t $@ + +# We need the following in order to create an empty placeholder for +# <unistd.h> when the system doesn't have one. +unistd.h: + echo '/* Empty placeholder for $@. */' >$@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..f4d783e2 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,53 @@ +## Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301 USA + +AM_CFLAGS = $(WARNING_CFLAGS) + +BUILT_SOURCES = +EXTRA_DIST = +MOSTLYCLEANFILES = + +lib_LIBRARIES = $(YACC_LIBRARY) +EXTRA_LIBRARIES = liby.a +noinst_LIBRARIES = libbison.a + +liby_a_SOURCES = main.c yyerror.c + +libbison_a_SOURCES = $(lib_SOURCES) +lib_SOURCES = \ + get-errno.h get-errno.c \ + subpipe.h subpipe.c \ + $(bitsets_sources) $(additional_bitsets_sources) $(timevars_sources) + +# Implementation of bitsets +bitsets_sources = \ + abitset.c abitset.h bbitset.h bitset.c bitset.h bitset_stats.c \ + bitset_stats.h bitsetv.c bitsetv.h ebitset.c ebitset.h lbitset.c \ + lbitset.h libiberty.h vbitset.c vbitset.h + +# Additional bitset operations. +additional_bitsets_sources = \ + bitsetv-print.h bitsetv-print.c + +# timevars, stolen from GCC. +timevars_sources = \ + timevar.h timevar.c timevar.def + +libbison_a_LIBADD = $(LIBOBJS) $(ALLOCA) +libbison_a_DEPENDENCIES = $(libbison_a_LIBADD) + +include gnulib.mk diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 00000000..d3613e96 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,623 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gnulib.mk dirname.c dirname.h dup-safer.c error.c \ + error.h exitfail.c exitfail.h fd-safer.c fopen-safer.c \ + getopt.c getopt1.c hard-locale.c hard-locale.h hash.c hash.h \ + malloc.c obstack.c obstack.h pipe-safer.c quote.c quote.h \ + quotearg.c quotearg.h stdio--.h stdio-safer.h stpcpy.c \ + strdup.c strdup.h strerror.c strndup.c strndup.h strnlen.c \ + strnlen.h strtol.c strtoul.c strverscmp.c strverscmp.h \ + unistd--.h unistd-safer.h unlocked-io.h xalloc.h xmalloc.c +subdir = lib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/bison-i18n.m4 \ + $(top_srcdir)/m4/c-working.m4 $(top_srcdir)/m4/cxx.m4 \ + $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dmalloc.m4 \ + $(top_srcdir)/m4/dos.m4 $(top_srcdir)/m4/error.m4 \ + $(top_srcdir)/m4/exitfail.m4 $(top_srcdir)/m4/extensions.m4 \ + $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/gettext_gl.m4 \ + $(top_srcdir)/m4/gnulib.m4 $(top_srcdir)/m4/hard-locale.m4 \ + $(top_srcdir)/m4/hash.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/inttypes_h_gl.m4 \ + $(top_srcdir)/m4/lib-ld_gl.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix_gl.m4 $(top_srcdir)/m4/m4.m4 \ + $(top_srcdir)/m4/mbrtowc.m4 $(top_srcdir)/m4/mbstate_t.m4 \ + $(top_srcdir)/m4/mbswidth.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/obstack.m4 $(top_srcdir)/m4/onceonly.m4 \ + $(top_srcdir)/m4/po_gl.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \ + $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint_h_gl.m4 \ + $(top_srcdir)/m4/stdio-safer.m4 $(top_srcdir)/m4/stpcpy.m4 \ + $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strerror.m4 \ + $(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/strnlen.m4 \ + $(top_srcdir)/m4/strtol.m4 $(top_srcdir)/m4/strtoul.m4 \ + $(top_srcdir)/m4/strverscmp.m4 $(top_srcdir)/m4/subpipe.m4 \ + $(top_srcdir)/m4/timevar.m4 $(top_srcdir)/m4/uintmax_t_gl.m4 \ + $(top_srcdir)/m4/ulonglong_gl.m4 \ + $(top_srcdir)/m4/unistd-safer.m4 $(top_srcdir)/m4/unistd_h.m4 \ + $(top_srcdir)/m4/unlocked-io.m4 $(top_srcdir)/m4/warning.m4 \ + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xstrndup.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLIBRARIES_INSTALL = $(INSTALL_DATA) +LIBRARIES = $(lib_LIBRARIES) $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libbison_a_AR = $(AR) $(ARFLAGS) +am__DEPENDENCIES_1 = @LIBOBJS@ +am__objects_1 = abitset.$(OBJEXT) bitset.$(OBJEXT) \ + bitset_stats.$(OBJEXT) bitsetv.$(OBJEXT) ebitset.$(OBJEXT) \ + lbitset.$(OBJEXT) vbitset.$(OBJEXT) +am__objects_2 = bitsetv-print.$(OBJEXT) +am__objects_3 = timevar.$(OBJEXT) +am__objects_4 = get-errno.$(OBJEXT) subpipe.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) argmatch.$(OBJEXT) \ + basename.$(OBJEXT) stripslash.$(OBJEXT) mbswidth.$(OBJEXT) \ + xalloc-die.$(OBJEXT) xstrndup.$(OBJEXT) +am_libbison_a_OBJECTS = $(am__objects_4) +libbison_a_OBJECTS = $(am_libbison_a_OBJECTS) +liby_a_AR = $(AR) $(ARFLAGS) +liby_a_LIBADD = +am_liby_a_OBJECTS = main.$(OBJEXT) yyerror.$(OBJEXT) +liby_a_OBJECTS = $(am_liby_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libbison_a_SOURCES) $(liby_a_SOURCES) +DIST_SOURCES = $(libbison_a_SOURCES) $(liby_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOM4TE = @AUTOM4TE@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BISON_CXX_WORKS = @BISON_CXX_WORKS@ +BISON_CXX_WORKS_FALSE = @BISON_CXX_WORKS_FALSE@ +BISON_CXX_WORKS_TRUE = @BISON_CXX_WORKS_TRUE@ +BISON_LOCALEDIR = @BISON_LOCALEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GCC = @GCC@ +GETOPT_H = @GETOPT_H@ +GMSGFMT = @GMSGFMT@ +HAVE__BOOL = @HAVE__BOOL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +M4 = @M4@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +O0CFLAGS = @O0CFLAGS@ +O0CXXFLAGS = @O0CXXFLAGS@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STDBOOL_H = @STDBOOL_H@ +STRIP = @STRIP@ +UNISTD_H = @UNISTD_H@ +USE_NLS = @USE_NLS@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +WARNING_CXXFLAGS = @WARNING_CXXFLAGS@ +WERROR_CFLAGS = @WERROR_CFLAGS@ +XGETTEXT = @XGETTEXT@ +YACC = @YACC@ +YACC_LIBRARY = @YACC_LIBRARY@ +YACC_SCRIPT = @YACC_SCRIPT@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +aclocaldir = @aclocaldir@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = $(WARNING_CFLAGS) +BUILT_SOURCES = $(GETOPT_H) $(STDBOOL_H) $(UNISTD_H) +EXTRA_DIST = getopt_.h getopt_int.h stdbool_.h +MOSTLYCLEANFILES = getopt.h getopt.h-t stdbool.h stdbool.h-t unistd.h +lib_LIBRARIES = $(YACC_LIBRARY) +EXTRA_LIBRARIES = liby.a +noinst_LIBRARIES = libbison.a +liby_a_SOURCES = main.c yyerror.c +libbison_a_SOURCES = $(lib_SOURCES) + +# This file is generated automatically by "bootstrap". + +# This is for those projects which use "gettextize --intl" to put a source-code +# copy of libintl into their package. In such projects, every Makefile.am needs +# -I$(top_builddir)/intl, so that <libintl.h> can be found in this directory. +# For the Makefile.ams in other directories it is the maintainer's +# responsibility; for the one from gnulib we do it here. +# This option has no effect when the user disables NLS (because then the intl +# directory contains no libintl.h file) or when the project does not use +# "gettextize --intl". +# (commented out by bootstrap) AM_CPPFLAGS += -I$(top_builddir)/intl +lib_SOURCES = get-errno.h get-errno.c subpipe.h subpipe.c \ + $(bitsets_sources) $(additional_bitsets_sources) \ + $(timevars_sources) argmatch.h argmatch.c basename.c \ + stripslash.c exit.h gettext.h mbswidth.h mbswidth.c stpcpy.h \ + verify.h xalloc-die.c xstrndup.h xstrndup.c + +# Implementation of bitsets +bitsets_sources = \ + abitset.c abitset.h bbitset.h bitset.c bitset.h bitset_stats.c \ + bitset_stats.h bitsetv.c bitsetv.h ebitset.c ebitset.h lbitset.c \ + lbitset.h libiberty.h vbitset.c vbitset.h + + +# Additional bitset operations. +additional_bitsets_sources = \ + bitsetv-print.h bitsetv-print.c + + +# timevars, stolen from GCC. +timevars_sources = \ + timevar.h timevar.c timevar.def + +libbison_a_LIBADD = $(LIBOBJS) $(ALLOCA) +libbison_a_DEPENDENCIES = $(libbison_a_LIBADD) +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/gnulib.mk $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + p=$(am__strip_dir) \ + echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ + $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbison.a: $(libbison_a_OBJECTS) $(libbison_a_DEPENDENCIES) + -rm -f libbison.a + $(libbison_a_AR) libbison.a $(libbison_a_OBJECTS) $(libbison_a_LIBADD) + $(RANLIB) libbison.a +liby.a: $(liby_a_OBJECTS) $(liby_a_DEPENDENCIES) + -rm -f liby.a + $(liby_a_AR) liby.a $(liby_a_OBJECTS) $(liby_a_LIBADD) + $(RANLIB) liby.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dirname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/dup-safer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/exitfail.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fd-safer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fopen-safer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/hard-locale.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/malloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/obstack.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pipe-safer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/quote.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/quotearg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/stpcpy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strdup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strerror.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strndup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strnlen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strtol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strtoul.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strverscmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/xmalloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/abitset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/argmatch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basename.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitset_stats.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitsetv-print.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitsetv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ebitset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get-errno.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lbitset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbswidth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stripslash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subpipe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timevar.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vbitset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xalloc-die.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstrndup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yyerror.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libLIBRARIES clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLIBRARIES clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-libLIBRARIES install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLIBRARIES + + +# We need the following in order to create <getopt.h> when the system +# doesn't have one that works with the given compiler. +getopt.h: getopt_.h + cp $(srcdir)/getopt_.h $@-t + mv $@-t $@ + +# We need the following in order to create <stdbool.h> when the system +# doesn't have one that works. +stdbool.h: stdbool_.h + sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h > $@-t + mv $@-t $@ + +# We need the following in order to create an empty placeholder for +# <unistd.h> when the system doesn't have one. +unistd.h: + echo '/* Empty placeholder for $@. */' >$@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/abitset.c b/lib/abitset.c new file mode 100644 index 00000000..17c0a4af --- /dev/null +++ b/lib/abitset.c @@ -0,0 +1,828 @@ +/* Array bitsets. + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "abitset.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +/* This file implements fixed size bitsets stored as an array + of words. Any unused bits in the last word must be zero. */ + +#define ABITSET_N_WORDS(N) (((N) + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) +#define ABITSET_WORDS(X) ((X)->a.words) + + +static bitset_bindex +abitset_resize (bitset src, bitset_bindex size) +{ + /* These bitsets have a fixed size. */ + if (BITSET_SIZE_ (src) != size) + abort (); + + return size; +} + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +abitset_small_list (bitset src, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex bitno; + bitset_bindex count; + bitset_windex size; + bitset_word word; + + word = ABITSET_WORDS (src)[0]; + + /* Short circuit common case. */ + if (!word) + return 0; + + size = BITSET_SIZE_ (src); + bitno = *next; + if (bitno >= size) + return 0; + + word >>= bitno; + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + if (num >= BITSET_WORD_BITS) + { + for (count = 0; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + else + { + for (count = 0; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + bitno++; + break; + } + } + word >>= 1; + } + } + + *next = bitno; + return count; +} + + +/* Set bit BITNO in bitset DST. */ +static void +abitset_set (bitset dst ATTRIBUTE_UNUSED, bitset_bindex bitno ATTRIBUTE_UNUSED) +{ + /* This should never occur for abitsets since we should always hit + the cache. It is likely someone is trying to access outside the + bounds of the bitset. */ + abort (); +} + + +/* Reset bit BITNO in bitset DST. */ +static void +abitset_reset (bitset dst ATTRIBUTE_UNUSED, + bitset_bindex bitno ATTRIBUTE_UNUSED) +{ + /* This should never occur for abitsets since we should always hit + the cache. It is likely someone is trying to access outside the + bounds of the bitset. Since the bit is zero anyway, let it pass. */ +} + + +/* Test bit BITNO in bitset SRC. */ +static bool +abitset_test (bitset src ATTRIBUTE_UNUSED, + bitset_bindex bitno ATTRIBUTE_UNUSED) +{ + /* This should never occur for abitsets since we should always + hit the cache. */ + return false; +} + + +/* Find list of up to NUM bits set in BSET in reverse order, starting + from and including NEXT and store in array LIST. Return with + actual number of bits found and with *NEXT indicating where search + stopped. */ +static bitset_bindex +abitset_list_reverse (bitset src, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex bitno; + bitset_bindex rbitno; + bitset_bindex count; + bitset_windex windex; + unsigned int bitcnt; + bitset_bindex bitoff; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_bindex n_bits = BITSET_SIZE_ (src); + + rbitno = *next; + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + if (rbitno >= n_bits) + return 0; + + count = 0; + + bitno = n_bits - (rbitno + 1); + + windex = bitno / BITSET_WORD_BITS; + bitcnt = bitno % BITSET_WORD_BITS; + bitoff = windex * BITSET_WORD_BITS; + + do + { + bitset_word word; + + word = srcp[windex] << (BITSET_WORD_BITS - 1 - bitcnt); + for (; word; bitcnt--) + { + if (word & BITSET_MSB) + { + list[count++] = bitoff + bitcnt; + if (count >= num) + { + *next = n_bits - (bitoff + bitcnt); + return count; + } + } + word <<= 1; + } + bitoff -= BITSET_WORD_BITS; + bitcnt = BITSET_WORD_BITS - 1; + } + while (windex--); + + *next = n_bits - (bitoff + 1); + return count; +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +abitset_list (bitset src, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex bitno; + bitset_bindex count; + bitset_windex windex; + bitset_bindex bitoff; + bitset_windex size = src->b.csize; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word word; + + bitno = *next; + + count = 0; + if (!bitno) + { + /* Many bitsets are zero, so make this common case fast. */ + for (windex = 0; windex < size && !srcp[windex]; windex++) + continue; + if (windex >= size) + return 0; + + /* If num is 1, we could speed things up with a binary search + of the current word. */ + + bitoff = windex * BITSET_WORD_BITS; + } + else + { + if (bitno >= BITSET_SIZE_ (src)) + return 0; + + windex = bitno / BITSET_WORD_BITS; + bitno = bitno % BITSET_WORD_BITS; + + if (bitno) + { + /* Handle the case where we start within a word. + Most often, this is executed with large bitsets + with many set bits where we filled the array + on the previous call to this function. */ + + bitoff = windex * BITSET_WORD_BITS; + word = srcp[windex] >> bitno; + for (bitno = bitoff + bitno; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + windex++; + } + bitoff = windex * BITSET_WORD_BITS; + } + + for (; windex < size; windex++, bitoff += BITSET_WORD_BITS) + { + if (!(word = srcp[windex])) + continue; + + if ((count + BITSET_WORD_BITS) < num) + { + for (bitno = bitoff; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + else + { + for (bitno = bitoff; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + } + } + + *next = bitoff; + return count; +} + + +/* Ensure that any unused bits within the last word are clear. */ +static inline void +abitset_unused_clear (bitset dst) +{ + unsigned int last_bit; + + last_bit = BITSET_SIZE_ (dst) % BITSET_WORD_BITS; + if (last_bit) + ABITSET_WORDS (dst)[dst->b.csize - 1] &= + ((bitset_word) 1 << last_bit) - 1; +} + + +static void +abitset_ones (bitset dst) +{ + bitset_word *dstp = ABITSET_WORDS (dst); + size_t bytes; + + bytes = sizeof (bitset_word) * dst->b.csize; + + memset (dstp, -1, bytes); + abitset_unused_clear (dst); +} + + +static void +abitset_zero (bitset dst) +{ + bitset_word *dstp = ABITSET_WORDS (dst); + size_t bytes; + + bytes = sizeof (bitset_word) * dst->b.csize; + + memset (dstp, 0, bytes); +} + + +static bool +abitset_empty_p (bitset dst) +{ + bitset_windex i; + bitset_word *dstp = ABITSET_WORDS (dst); + + for (i = 0; i < dst->b.csize; i++) + if (dstp[i]) + return false; + + return true; +} + + +static void +abitset_copy1 (bitset dst, bitset src) +{ + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + if (srcp == dstp) + return; + memcpy (dstp, srcp, sizeof (bitset_word) * size); +} + + +static void +abitset_not (bitset dst, bitset src) +{ + bitset_windex i; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = ~(*srcp++); + abitset_unused_clear (dst); +} + + +static bool +abitset_equal_p (bitset dst, bitset src) +{ + bitset_windex i; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + if (*srcp++ != *dstp++) + return false; + return true; +} + + +static bool +abitset_subset_p (bitset dst, bitset src) +{ + bitset_windex i; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++, srcp++) + if (*dstp != (*srcp | *dstp)) + return false; + return true; +} + + +static bool +abitset_disjoint_p (bitset dst, bitset src) +{ + bitset_windex i; + bitset_word *srcp = ABITSET_WORDS (src); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + if (*srcp++ & *dstp++) + return false; + + return true; +} + + +static void +abitset_and (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = *src1p++ & *src2p++; +} + + +static bool +abitset_and_cmp (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = *src1p++ & *src2p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_andn (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = *src1p++ & ~(*src2p++); +} + + +static bool +abitset_andn_cmp (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = *src1p++ & ~(*src2p++); + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_or (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = *src1p++ | *src2p++; +} + + +static bool +abitset_or_cmp (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = *src1p++ | *src2p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_xor (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = *src1p++ ^ *src2p++; +} + + +static bool +abitset_xor_cmp (bitset dst, bitset src1, bitset src2) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = *src1p++ ^ *src2p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_and_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ & *src2p++) | *src3p++; +} + + +static bool +abitset_and_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ & *src2p++) | *src3p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_andn_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ & ~(*src2p++)) | *src3p++; +} + + +static bool +abitset_andn_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ & ~(*src2p++)) | *src3p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_or_and (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ | *src2p++) & *src3p++; +} + + +static bool +abitset_or_and_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_windex i; + bool changed = false; + bitset_word *src1p = ABITSET_WORDS (src1); + bitset_word *src2p = ABITSET_WORDS (src2); + bitset_word *src3p = ABITSET_WORDS (src3); + bitset_word *dstp = ABITSET_WORDS (dst); + bitset_windex size = dst->b.csize; + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ | *src2p++) & *src3p++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + return changed; +} + + +static void +abitset_copy (bitset dst, bitset src) +{ + if (BITSET_COMPATIBLE_ (dst, src)) + abitset_copy1 (dst, src); + else + bitset_copy_ (dst, src); +} + + +/* Vector of operations for single word bitsets. */ +struct bitset_vtable abitset_small_vtable = { + abitset_set, + abitset_reset, + bitset_toggle_, + abitset_test, + abitset_resize, + bitset_size_, + bitset_count_, + abitset_empty_p, + abitset_ones, + abitset_zero, + abitset_copy, + abitset_disjoint_p, + abitset_equal_p, + abitset_not, + abitset_subset_p, + abitset_and, + abitset_and_cmp, + abitset_andn, + abitset_andn_cmp, + abitset_or, + abitset_or_cmp, + abitset_xor, + abitset_xor_cmp, + abitset_and_or, + abitset_and_or_cmp, + abitset_andn_or, + abitset_andn_or_cmp, + abitset_or_and, + abitset_or_and_cmp, + abitset_small_list, + abitset_list_reverse, + NULL, + BITSET_ARRAY +}; + + +/* Vector of operations for multiple word bitsets. */ +struct bitset_vtable abitset_vtable = { + abitset_set, + abitset_reset, + bitset_toggle_, + abitset_test, + abitset_resize, + bitset_size_, + bitset_count_, + abitset_empty_p, + abitset_ones, + abitset_zero, + abitset_copy, + abitset_disjoint_p, + abitset_equal_p, + abitset_not, + abitset_subset_p, + abitset_and, + abitset_and_cmp, + abitset_andn, + abitset_andn_cmp, + abitset_or, + abitset_or_cmp, + abitset_xor, + abitset_xor_cmp, + abitset_and_or, + abitset_and_or_cmp, + abitset_andn_or, + abitset_andn_or_cmp, + abitset_or_and, + abitset_or_and_cmp, + abitset_list, + abitset_list_reverse, + NULL, + BITSET_ARRAY +}; + + +size_t +abitset_bytes (bitset_bindex n_bits) +{ + bitset_windex size; + size_t bytes; + size_t header_size = offsetof (union bitset_union, a.words); + struct bitset_align_struct { char a; union bitset_union b; }; + size_t bitset_alignment = offsetof (struct bitset_align_struct, b); + + size = ABITSET_N_WORDS (n_bits); + bytes = header_size + size * sizeof (bitset_word); + + /* Align the size properly for a vector of abitset objects. */ + if (header_size % bitset_alignment != 0 + || sizeof (bitset_word) % bitset_alignment != 0) + { + bytes += bitset_alignment - 1; + bytes -= bytes % bitset_alignment; + } + + return bytes; +} + + +bitset +abitset_init (bitset bset, bitset_bindex n_bits) +{ + bitset_windex size; + + size = ABITSET_N_WORDS (n_bits); + BITSET_NBITS_ (bset) = n_bits; + + /* Use optimized routines if bitset fits within a single word. + There is probably little merit if using caching since + the small bitset will always fit in the cache. */ + if (size == 1) + bset->b.vtable = &abitset_small_vtable; + else + bset->b.vtable = &abitset_vtable; + + bset->b.cindex = 0; + bset->b.csize = size; + bset->b.cdata = ABITSET_WORDS (bset); + return bset; +} diff --git a/lib/abitset.h b/lib/abitset.h new file mode 100644 index 00000000..a22c9191 --- /dev/null +++ b/lib/abitset.h @@ -0,0 +1,28 @@ +/* Functions to support abitsets. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _ABITSET_H +#define _ABITSET_H + +#include "bitset.h" + +extern size_t abitset_bytes (bitset_bindex); + +extern bitset abitset_init (bitset, bitset_bindex); + +#endif diff --git a/lib/argmatch.c b/lib/argmatch.c new file mode 100644 index 00000000..36d5845a --- /dev/null +++ b/lib/argmatch.c @@ -0,0 +1,281 @@ +/* argmatch.c -- find a match for a string in an array + + Copyright (C) 1990, 1998, 1999, 2001, 2002, 2003, 2004, 2005 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by David MacKenzie <djm@ai.mit.edu> + Modified by Akim Demaille <demaille@inf.enst.fr> */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "argmatch.h" + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +#include "error.h" +#include "exit.h" +#include "quotearg.h" +#include "quote.h" + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +/* When reporting an invalid argument, show nonprinting characters + by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use + literal_quoting_style. */ +#ifndef ARGMATCH_QUOTING_STYLE +# define ARGMATCH_QUOTING_STYLE locale_quoting_style +#endif + +/* Non failing version of argmatch call this function after failing. */ +#ifndef ARGMATCH_DIE +# include "exitfail.h" +# define ARGMATCH_DIE exit (exit_failure) +#endif + +#ifdef ARGMATCH_DIE_DECL +ARGMATCH_DIE_DECL; +#endif + +static void +__argmatch_die (void) +{ + ARGMATCH_DIE; +} + +/* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h. + Default to __argmatch_die, but allow caller to change this at run-time. */ +argmatch_exit_fn argmatch_die = __argmatch_die; + + +/* If ARG is an unambiguous match for an element of the + NULL-terminated array ARGLIST, return the index in ARGLIST + of the matched element, else -1 if it does not match any element + or -2 if it is ambiguous (is a prefix of more than one element). + + If VALLIST is none null, use it to resolve ambiguities limited to + synonyms, i.e., for + "yes", "yop" -> 0 + "no", "nope" -> 1 + "y" is a valid argument, for `0', and "n" for `1'. */ + +ptrdiff_t +argmatch (const char *arg, const char *const *arglist, + const char *vallist, size_t valsize) +{ + size_t i; /* Temporary index in ARGLIST. */ + size_t arglen; /* Length of ARG. */ + ptrdiff_t matchind = -1; /* Index of first nonexact match. */ + bool ambiguous = false; /* If true, multiple nonexact match(es). */ + + arglen = strlen (arg); + + /* Test all elements for either exact match or abbreviated matches. */ + for (i = 0; arglist[i]; i++) + { + if (!strncmp (arglist[i], arg, arglen)) + { + if (strlen (arglist[i]) == arglen) + /* Exact match found. */ + return i; + else if (matchind == -1) + /* First nonexact match found. */ + matchind = i; + else + { + /* Second nonexact match found. */ + if (vallist == NULL + || memcmp (vallist + valsize * matchind, + vallist + valsize * i, valsize)) + { + /* There is a real ambiguity, or we could not + disambiguate. */ + ambiguous = true; + } + } + } + } + if (ambiguous) + return -2; + else + return matchind; +} + +/* Error reporting for argmatch. + CONTEXT is a description of the type of entity that was being matched. + VALUE is the invalid value that was given. + PROBLEM is the return value from argmatch. */ + +void +argmatch_invalid (const char *context, const char *value, ptrdiff_t problem) +{ + char const *format = (problem == -1 + ? _("invalid argument %s for %s") + : _("ambiguous argument %s for %s")); + + error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value), + quote_n (1, context)); +} + +/* List the valid arguments for argmatch. + ARGLIST is the same as in argmatch. + VALLIST is a pointer to an array of values. + VALSIZE is the size of the elements of VALLIST */ +void +argmatch_valid (const char *const *arglist, + const char *vallist, size_t valsize) +{ + size_t i; + const char *last_val = NULL; + + /* We try to put synonyms on the same line. The assumption is that + synonyms follow each other */ + fprintf (stderr, _("Valid arguments are:")); + for (i = 0; arglist[i]; i++) + if ((i == 0) + || memcmp (last_val, vallist + valsize * i, valsize)) + { + fprintf (stderr, "\n - `%s'", arglist[i]); + last_val = vallist + valsize * i; + } + else + { + fprintf (stderr, ", `%s'", arglist[i]); + } + putc ('\n', stderr); +} + +/* Never failing versions of the previous functions. + + CONTEXT is the context for which argmatch is called (e.g., + "--version-control", or "$VERSION_CONTROL" etc.). Upon failure, + calls the (supposed never to return) function EXIT_FN. */ + +ptrdiff_t +__xargmatch_internal (const char *context, + const char *arg, const char *const *arglist, + const char *vallist, size_t valsize, + argmatch_exit_fn exit_fn) +{ + ptrdiff_t res = argmatch (arg, arglist, vallist, valsize); + if (res >= 0) + /* Success. */ + return res; + + /* We failed. Explain why. */ + argmatch_invalid (context, arg, res); + argmatch_valid (arglist, vallist, valsize); + (*exit_fn) (); + + return -1; /* To please the compilers. */ +} + +/* Look for VALUE in VALLIST, an array of objects of size VALSIZE and + return the first corresponding argument in ARGLIST */ +const char * +argmatch_to_argument (const char *value, + const char *const *arglist, + const char *vallist, size_t valsize) +{ + size_t i; + + for (i = 0; arglist[i]; i++) + if (!memcmp (value, vallist + valsize * i, valsize)) + return arglist[i]; + return NULL; +} + +#ifdef TEST +/* + * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu> + */ +char *program_name; + +/* When to make backup files. */ +enum backup_type +{ + /* Never make backups. */ + no_backups, + + /* Make simple backups of every file. */ + simple_backups, + + /* Make numbered backups of files that already have numbered backups, + and simple backups of the others. */ + numbered_existing_backups, + + /* Make numbered backups of every file. */ + numbered_backups +}; + +/* Two tables describing arguments (keys) and their corresponding + values */ +static const char *const backup_args[] = +{ + "no", "none", "off", + "simple", "never", + "existing", "nil", + "numbered", "t", + 0 +}; + +static const enum backup_type backup_vals[] = +{ + no_backups, no_backups, no_backups, + simple_backups, simple_backups, + numbered_existing_backups, numbered_existing_backups, + numbered_backups, numbered_backups +}; + +int +main (int argc, const char *const *argv) +{ + const char *cp; + enum backup_type backup_type = no_backups; + + program_name = (char *) argv[0]; + + if (argc > 2) + { + fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name); + exit (1); + } + + if ((cp = getenv ("VERSION_CONTROL"))) + backup_type = XARGMATCH ("$VERSION_CONTROL", cp, + backup_args, backup_vals); + + if (argc == 2) + backup_type = XARGMATCH (program_name, argv[1], + backup_args, backup_vals); + + printf ("The version control is `%s'\n", + ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals)); + + return 0; +} +#endif diff --git a/lib/argmatch.h b/lib/argmatch.h new file mode 100644 index 00000000..f2dfe59b --- /dev/null +++ b/lib/argmatch.h @@ -0,0 +1,103 @@ +/* argmatch.h -- definitions and prototypes for argmatch.c + + Copyright (C) 1990, 1998, 1999, 2001, 2002, 2004, 2005 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by David MacKenzie <djm@ai.mit.edu> + Modified by Akim Demaille <demaille@inf.enst.fr> */ + +#ifndef ARGMATCH_H_ +# define ARGMATCH_H_ 1 + +# include <stddef.h> + +# include "verify.h" + +# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) + +/* Assert there are as many real arguments as there are values + (argument list ends with a NULL guard). */ + +# define ARGMATCH_VERIFY(Arglist, Vallist) \ + verify (ARRAY_CARDINALITY (Arglist) == ARRAY_CARDINALITY (Vallist) + 1) + +/* Return the index of the element of ARGLIST (NULL terminated) that + matches with ARG. If VALLIST is not NULL, then use it to resolve + false ambiguities (i.e., different matches of ARG but corresponding + to the same values in VALLIST). */ + +ptrdiff_t argmatch (char const *arg, char const *const *arglist, + char const *vallist, size_t valsize); + +# define ARGMATCH(Arg, Arglist, Vallist) \ + argmatch (Arg, Arglist, (char const *) (Vallist), sizeof *(Vallist)) + +/* xargmatch calls this function when it fails. This function should not + return. By default, this is a function that calls ARGMATCH_DIE which + in turn defaults to `exit (exit_failure)'. */ +typedef void (*argmatch_exit_fn) (void); +extern argmatch_exit_fn argmatch_die; + +/* Report on stderr why argmatch failed. Report correct values. */ + +void argmatch_invalid (char const *context, char const *value, + ptrdiff_t problem); + +/* Left for compatibility with the old name invalid_arg */ + +# define invalid_arg(Context, Value, Problem) \ + argmatch_invalid (Context, Value, Problem) + + + +/* Report on stderr the list of possible arguments. */ + +void argmatch_valid (char const *const *arglist, + char const *vallist, size_t valsize); + +# define ARGMATCH_VALID(Arglist, Vallist) \ + argmatch_valid (Arglist, (char const *) (Vallist), sizeof *(Vallist)) + + + +/* Same as argmatch, but upon failure, reports a explanation on the + failure, and exits using the function EXIT_FN. */ + +ptrdiff_t __xargmatch_internal (char const *context, + char const *arg, char const *const *arglist, + char const *vallist, size_t valsize, + argmatch_exit_fn exit_fn); + +/* Programmer friendly interface to __xargmatch_internal. */ + +# define XARGMATCH(Context, Arg, Arglist, Vallist) \ + ((Vallist) [__xargmatch_internal (Context, Arg, Arglist, \ + (char const *) (Vallist), \ + sizeof *(Vallist), \ + argmatch_die)]) + +/* Convert a value into a corresponding argument. */ + +char const *argmatch_to_argument (char const *value, + char const *const *arglist, + char const *vallist, size_t valsize); + +# define ARGMATCH_TO_ARGUMENT(Value, Arglist, Vallist) \ + argmatch_to_argument (Value, Arglist, \ + (char const *) (Vallist), sizeof *(Vallist)) + +#endif /* ARGMATCH_H_ */ diff --git a/lib/basename.c b/lib/basename.c new file mode 100644 index 00000000..5cc97cd4 --- /dev/null +++ b/lib/basename.c @@ -0,0 +1,79 @@ +/* basename.c -- return the last element in a file name + + Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" +#include <string.h> + +/* In general, we can't use the builtin `basename' function if available, + since it has different meanings in different environments. + In some environments the builtin `basename' modifies its argument. + + Return the address of the last file name component of NAME. If + NAME has no file name components because it is all slashes, return + NAME if it is empty, the address of its last slash otherwise. */ + +char * +base_name (char const *name) +{ + char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); + char const *p; + + for (p = base; *p; p++) + { + if (ISSLASH (*p)) + { + /* Treat multiple adjacent slashes like a single slash. */ + do p++; + while (ISSLASH (*p)); + + /* If the file name ends in slash, use the trailing slash as + the basename if no non-slashes have been found. */ + if (! *p) + { + if (ISSLASH (*base)) + base = p - 1; + break; + } + + /* *P is a non-slash preceded by a slash. */ + base = p; + } + } + + return (char *) base; +} + +/* Return the length of of the basename NAME. Typically NAME is the + value returned by base_name. Act like strlen (NAME), except omit + redundant trailing slashes. */ + +size_t +base_len (char const *name) +{ + size_t len; + + for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) + continue; + + return len; +} diff --git a/lib/bbitset.h b/lib/bbitset.h new file mode 100644 index 00000000..956fc5c6 --- /dev/null +++ b/lib/bbitset.h @@ -0,0 +1,302 @@ +/* Base bitset stuff. + Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BBITSET_H +#define _BBITSET_H + +#include "libiberty.h" + +#include <stdbool.h> +#include <limits.h> +#include <stddef.h> + +/* Currently we support five flavours of bitsets: + BITSET_ARRAY: Array of bits (fixed size, fast for dense bitsets). + Memory for bit array and bitset structure allocated + contiguously. + BITSET_LIST: Linked list of arrays of bits (variable size, least storage + for large very sparse sets). + BITSET_TABLE: Expandable table of pointers to arrays of bits + (variable size, less storage for large sparse sets). + Faster than BITSET_LIST for random access. + BITSET_VARRAY: Variable array of bits (variable size, fast for + dense bitsets). + BITSET_STATS: Wrapper bitset for internal use only. Used for gathering + statistics and/or better run-time checking. +*/ +enum bitset_type {BITSET_ARRAY, BITSET_LIST, BITSET_TABLE, BITSET_VARRAY, + BITSET_TYPE_NUM, BITSET_STATS}; +#define BITSET_TYPE_NAMES {"abitset", "lbitset", "ebitset", "vbitset"} + +extern const char * const bitset_type_names[]; + +enum bitset_alloc_type {BITSET_MALLOC, BITSET_OBALLOC}; + +/* Data type used to store a word of bits. */ +typedef unsigned long int bitset_word; +#define BITSET_WORD_BITS ((unsigned int) (CHAR_BIT * sizeof (bitset_word))) + +/* Bit index. In theory we might need a type wider than size_t, but + in practice we lose at most a factor of CHAR_BIT by going with + size_t, and that is good enough. If this type is changed to be + wider than size_t, the code needs to be modified to check for + overflow when converting bit counts to byte or word counts. + The bit and word index types must be unsigned. */ +typedef size_t bitset_bindex; + +/* Word index. */ +typedef size_t bitset_windex; + +/* Maximum values for commonly-used unsigned types. BITSET_SIZE_MAX + always equals SIZE_MAX, but some older systems lack SIZE_MAX. */ +#define BITSET_BINDEX_MAX ((bitset_bindex) -1) + +/* Limit max word index to the maximum value of a signed integer + to simplify cache disabling. */ +#define BITSET_WINDEX_MAX (((bitset_windex) -1) >> 1) +#define BITSET_SIZE_MAX ((size_t) -1) + +#define BITSET_MSB ((bitset_word) 1 << (BITSET_WORD_BITS - 1)) + +#define BITSET_LIST_SIZE 1024 + +enum bitset_ops {BITSET_OP_ZERO, BITSET_OP_ONES, + BITSET_OP_COPY, BITSET_OP_NOT, + BITSET_OP_EMPTY_P, BITSET_OP_EQUAL_P, + BITSET_OP_SUBSET_P, BITSET_OP_DISJOINT_P, + BITSET_OP_AND, BITSET_OP_OR, BITSET_OP_XOR, BITSET_OP_ANDN, + BITSET_OP_OR_AND, BITSET_OP_AND_OR, BITSET_OP_ANDN_OR}; + +struct bbitset_struct +{ + const struct bitset_vtable *vtable; + bitset_windex cindex; /* Cache word index. */ + bitset_windex csize; /* Cache size in words. */ + bitset_word *cdata; /* Cache data pointer. */ + bitset_bindex n_bits; /* Number of bits. */ + /* Perhaps we could sacrifice another word to indicate + that the bitset is known to be zero, that a bit has been set + in the cache, and that a bit has been cleared in the cache. + This would speed up some of the searches but slightly slow down + bit set/reset operations of cached bits. */ +}; + + +typedef union bitset_union *bitset; + + +/* Private accessor macros to bitset structure. */ +#define BITSET_VTABLE_(SRC) (SRC)->b.vtable +#define BITSET_CINDEX_(SRC) (SRC)->b.cindex +#define BITSET_CDATA_(SRC) (SRC)->b.cdata +#define BITSET_CSIZE_(SRC) (SRC)->b.csize +#define BITSET_NBITS_(SRC) (SRC)->b.n_bits + + +/* The contents of this structure should be considered private. */ +struct bitset_vtable +{ + void (*set) (bitset, bitset_bindex); + void (*reset) (bitset, bitset_bindex); + bool (*toggle) (bitset, bitset_bindex); + bool (*test) (bitset, bitset_bindex); + bitset_bindex (*resize) (bitset, bitset_bindex); + bitset_bindex (*size) (bitset); + bitset_bindex (*count) (bitset); + + bool (*empty_p) (bitset); + void (*ones) (bitset); + void (*zero) (bitset); + + void (*copy) (bitset, bitset); + bool (*disjoint_p) (bitset, bitset); + bool (*equal_p) (bitset, bitset); + void (*not_) (bitset, bitset); + bool (*subset_p) (bitset, bitset); + + void (*and_) (bitset, bitset, bitset); + bool (*and_cmp) (bitset, bitset, bitset); + void (*andn) (bitset, bitset, bitset); + bool (*andn_cmp) (bitset, bitset, bitset); + void (*or_) (bitset, bitset, bitset); + bool (*or_cmp) (bitset, bitset, bitset); + void (*xor_) (bitset, bitset, bitset); + bool (*xor_cmp) (bitset, bitset, bitset); + + void (*and_or) (bitset, bitset, bitset, bitset); + bool (*and_or_cmp) (bitset, bitset, bitset, bitset); + void (*andn_or) (bitset, bitset, bitset, bitset); + bool (*andn_or_cmp) (bitset, bitset, bitset, bitset); + void (*or_and) (bitset, bitset, bitset, bitset); + bool (*or_and_cmp) (bitset, bitset, bitset, bitset); + + bitset_bindex (*list) (bitset, bitset_bindex *, bitset_bindex, + bitset_bindex *); + bitset_bindex (*list_reverse) (bitset, bitset_bindex *, bitset_bindex, + bitset_bindex *); + void (*free) (bitset); + enum bitset_type type; +}; + +#define BITSET_COMPATIBLE_(BSET1, BSET2) \ +((BSET1)->b.vtable == (BSET2)->b.vtable) + +#define BITSET_CHECK2_(DST, SRC) \ +if (!BITSET_COMPATIBLE_ (DST, SRC)) abort (); + +#define BITSET_CHECK3_(DST, SRC1, SRC2) \ +if (!BITSET_COMPATIBLE_ (DST, SRC1) \ + || !BITSET_COMPATIBLE_ (DST, SRC2)) abort (); + +#define BITSET_CHECK4_(DST, SRC1, SRC2, SRC3) \ +if (!BITSET_COMPATIBLE_ (DST, SRC1) || !BITSET_COMPATIBLE_ (DST, SRC2) \ + || !BITSET_COMPATIBLE_ (DST, SRC3)) abort (); + + +/* Redefine number of bits in bitset DST. */ +#define BITSET_RESIZE_(DST, SIZE) (DST)->b.vtable->resize (DST, SIZE) + +/* Return size in bits of bitset SRC. */ +#define BITSET_SIZE_(SRC) (SRC)->b.vtable->size (SRC) + +/* Return number of bits set in bitset SRC. */ +#define BITSET_COUNT_(SRC) (SRC)->b.vtable->count (SRC) + +/* Return type of bitset SRC. */ +#define BITSET_TYPE_(DST) (DST)->b.vtable->type + +/* Set bit BITNO in bitset DST. */ +#define BITSET_SET_(DST, BITNO) (DST)->b.vtable->set (DST, BITNO) + +/* Reset bit BITNO in bitset DST. */ +#define BITSET_RESET_(DST, BITNO) (DST)->b.vtable->reset (DST, BITNO) + +/* Toggle bit BITNO in bitset DST. */ +#define BITSET_TOGGLE_(DST, BITNO) (DST)->b.vtable->toggle (DST, BITNO) + +/* Return non-zero if bit BITNO in bitset SRC is set. */ +#define BITSET_TEST_(SRC, BITNO) (SRC)->b.vtable->test (SRC, BITNO) + +/* Free bitset SRC. */ +#define BITSET_FREE_(SRC)\ + ((SRC)->b.vtable->free ? (SRC)->b.vtable->free (SRC) :(void)0) + + +/* Return SRC == 0. */ +#define BITSET_EMPTY_P_(SRC) (SRC)->b.vtable->empty_p (SRC) + +/* DST = ~0. */ +#define BITSET_ONES_(DST) (DST)->b.vtable->ones (DST) + +/* DST = 0. */ +#define BITSET_ZERO_(DST) (DST)->b.vtable->zero (DST) + + + +/* DST = SRC. */ +#define BITSET_COPY_(DST, SRC) (SRC)->b.vtable->copy (DST, SRC) + +/* Return DST & SRC == 0. */ +#define BITSET_DISJOINT_P_(DST, SRC) (SRC)->b.vtable->disjoint_p (DST, SRC) + +/* Return DST == SRC. */ +#define BITSET_EQUAL_P_(DST, SRC) (SRC)->b.vtable->equal_p (DST, SRC) + +/* DST = ~SRC. */ +#define BITSET_NOT_(DST, SRC) (SRC)->b.vtable->not_ (DST, SRC) + +/* Return DST == DST | SRC. */ +#define BITSET_SUBSET_P_(DST, SRC) (SRC)->b.vtable->subset_p (DST, SRC) + + +/* DST = SRC1 & SRC2. */ +#define BITSET_AND_(DST, SRC1, SRC2) (SRC1)->b.vtable->and_ (DST, SRC1, SRC2) +#define BITSET_AND_CMP_(DST, SRC1, SRC2) (SRC1)->b.vtable->and_cmp (DST, SRC1, SRC2) + +/* DST = SRC1 & ~SRC2. */ +#define BITSET_ANDN_(DST, SRC1, SRC2) (SRC1)->b.vtable->andn (DST, SRC1, SRC2) +#define BITSET_ANDN_CMP_(DST, SRC1, SRC2) (SRC1)->b.vtable->andn_cmp (DST, SRC1, SRC2) + +/* DST = SRC1 | SRC2. */ +#define BITSET_OR_(DST, SRC1, SRC2) (SRC1)->b.vtable->or_ (DST, SRC1, SRC2) +#define BITSET_OR_CMP_(DST, SRC1, SRC2) (SRC1)->b.vtable->or_cmp (DST, SRC1, SRC2) + +/* DST = SRC1 ^ SRC2. */ +#define BITSET_XOR_(DST, SRC1, SRC2) (SRC1)->b.vtable->xor_ (DST, SRC1, SRC2) +#define BITSET_XOR_CMP_(DST, SRC1, SRC2) (SRC1)->b.vtable->xor_cmp (DST, SRC1, SRC2) + + + +/* DST = (SRC1 & SRC2) | SRC3. Return non-zero if + DST != (SRC1 & SRC2) | SRC3. */ +#define BITSET_AND_OR_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->and_or (DST, SRC1, SRC2, SRC3) +#define BITSET_AND_OR_CMP_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->and_or_cmp (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 & ~SRC2) | SRC3. Return non-zero if + DST != (SRC1 & ~SRC2) | SRC3. */ +#define BITSET_ANDN_OR_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->andn_or (DST, SRC1, SRC2, SRC3) +#define BITSET_ANDN_OR_CMP_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->andn_or_cmp (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 | SRC2) & SRC3. Return non-zero if + DST != (SRC1 | SRC2) & SRC3. */ +#define BITSET_OR_AND_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->or_and (DST, SRC1, SRC2, SRC3) +#define BITSET_OR_AND_CMP_(DST, SRC1, SRC2, SRC3) \ + (SRC1)->b.vtable->or_and_cmp (DST, SRC1, SRC2, SRC3) + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT. Return with actual number of bits found and with *NEXT + indicating where search stopped. */ +#define BITSET_LIST_(BSET, LIST, NUM, NEXT) \ + (BSET)->b.vtable->list (BSET, LIST, NUM, NEXT) + +/* Find reverse list of up to NUM bits set in BSET starting from and + including NEXT. Return with actual number of bits found and with + *NEXT indicating where search stopped. */ +#define BITSET_LIST_REVERSE_(BSET, LIST, NUM, NEXT) \ + (BSET)->b.vtable->list_reverse (BSET, LIST, NUM, NEXT) + + +/* Private functions for bitset implementations. */ + +extern bool bitset_toggle_ (bitset, bitset_bindex); + +extern bitset_bindex bitset_count_ (bitset); + +extern bitset_bindex bitset_size_ (bitset); + +extern bool bitset_copy_ (bitset, bitset); + +extern void bitset_and_or_ (bitset, bitset, bitset, bitset); + +extern bool bitset_and_or_cmp_ (bitset, bitset, bitset, bitset); + +extern void bitset_andn_or_ (bitset, bitset, bitset, bitset); + +extern bool bitset_andn_or_cmp_ (bitset, bitset, bitset, bitset); + +extern void bitset_or_and_ (bitset, bitset, bitset, bitset); + +extern bool bitset_or_and_cmp_ (bitset, bitset, bitset, bitset); + +#endif /* _BBITSET_H */ diff --git a/lib/bitset.c b/lib/bitset.c new file mode 100644 index 00000000..2924567e --- /dev/null +++ b/lib/bitset.c @@ -0,0 +1,505 @@ +/* General bitsets. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include "bitset.h" +#include "abitset.h" +#include "lbitset.h" +#include "ebitset.h" +#include "vbitset.h" +#include "bitset_stats.h" +#include "obstack.h" + +const char * const bitset_type_names[] = BITSET_TYPE_NAMES; + + +/* Return number of bytes required to create a N_BIT bitset + of TYPE. The bitset may grow to require more bytes than this. */ +size_t +bitset_bytes (enum bitset_type type, bitset_bindex n_bits) +{ + size_t bytes; + + if (bitset_stats_enabled) + return bitset_stats_bytes (); + + switch (type) + { + default: + abort (); + + case BITSET_ARRAY: + bytes = abitset_bytes (n_bits); + break; + + case BITSET_LIST: + bytes = lbitset_bytes (n_bits); + break; + + case BITSET_TABLE: + bytes = ebitset_bytes (n_bits); + break; + + case BITSET_VARRAY: + bytes = vbitset_bytes (n_bits); + break; + } + + return bytes; +} + + +/* Initialise bitset BSET of TYPE for N_BITS. */ +bitset +bitset_init (bitset bset, bitset_bindex n_bits, enum bitset_type type) +{ + if (bitset_stats_enabled) + return bitset_stats_init (bset, n_bits, type); + + switch (type) + { + default: + abort (); + + case BITSET_ARRAY: + return abitset_init (bset, n_bits); + + case BITSET_LIST: + return lbitset_init (bset, n_bits); + + case BITSET_TABLE: + return ebitset_init (bset, n_bits); + + case BITSET_VARRAY: + return vbitset_init (bset, n_bits); + } +} + + +/* Select a bitset type for a set of N_BITS and with attribute hints + specified by ATTR. For variable size bitsets, N_BITS is only a + hint and may be zero. */ +enum bitset_type +bitset_type_choose (bitset_bindex n_bits ATTRIBUTE_UNUSED, unsigned int attr) +{ + /* Check attributes. */ + if (attr & BITSET_FIXED && attr & BITSET_VARIABLE) + abort (); + if (attr & BITSET_SPARSE && attr & BITSET_DENSE) + abort (); + + /* Choose the type of bitset. Note that sometimes we will be asked + for a zero length fixed size bitset. */ + + + /* If no attributes selected, choose a good compromise. */ + if (!attr) + return BITSET_VARRAY; + + if (attr & BITSET_SPARSE) + return BITSET_LIST; + + if (attr & BITSET_FIXED) + return BITSET_ARRAY; + + if (attr & BITSET_GREEDY) + return BITSET_TABLE; + + return BITSET_VARRAY; +} + + +/* Create a bitset of N_BITS of type TYPE. */ +bitset +bitset_alloc (bitset_bindex n_bits, enum bitset_type type) +{ + size_t bytes; + bitset bset; + + bytes = bitset_bytes (type, n_bits); + + bset = xcalloc (1, bytes); + + /* The cache is disabled until some elements are allocated. If we + have variable length arrays, then we may need to allocate a dummy + element. */ + + return bitset_init (bset, n_bits, type); +} + + +/* Create a bitset of N_BITS of type TYPE. */ +bitset +bitset_obstack_alloc (struct obstack *bobstack, + bitset_bindex n_bits, enum bitset_type type) +{ + size_t bytes; + bitset bset; + + bytes = bitset_bytes (type, n_bits); + + bset = obstack_alloc (bobstack, bytes); + memset (bset, 0, bytes); + + return bitset_init (bset, n_bits, type); +} + + +/* Create a bitset of N_BITS and with attribute hints specified by + ATTR. */ +bitset +bitset_create (bitset_bindex n_bits, unsigned int attr) +{ + enum bitset_type type; + + type = bitset_type_choose (n_bits, attr); + + return bitset_alloc (n_bits, type); +} + + +/* Free bitset BSET. */ +void +bitset_free (bitset bset) +{ + BITSET_FREE_ (bset); + free (bset); +} + + +/* Free bitset BSET allocated on obstack. */ +void +bitset_obstack_free (bitset bset) +{ + BITSET_FREE_ (bset); +} + + +/* Return bitset type. */ +enum bitset_type +bitset_type_get (bitset bset) +{ + enum bitset_type type; + + type = BITSET_TYPE_ (bset); + if (type != BITSET_STATS) + return type; + + return bitset_stats_type_get (bset); +} + + +/* Return name of bitset type. */ +const char * +bitset_type_name_get (bitset bset) +{ + enum bitset_type type; + + type = bitset_type_get (bset); + + return bitset_type_names[type]; +} + + +/* Find next bit set in SRC starting from and including BITNO. + Return BITSET_BINDEX_MAX if SRC empty. */ +bitset_bindex +bitset_next (bitset src, bitset_bindex bitno) +{ + bitset_bindex val; + bitset_bindex next = bitno; + + if (!bitset_list (src, &val, 1, &next)) + return BITSET_BINDEX_MAX; + return val; +} + + +/* Return true if both bitsets are of the same type and size. */ +extern bool +bitset_compatible_p (bitset bset1, bitset bset2) +{ + return BITSET_COMPATIBLE_ (bset1, bset2); +} + + +/* Find previous bit set in SRC starting from and including BITNO. + Return BITSET_BINDEX_MAX if SRC empty. */ +bitset_bindex +bitset_prev (bitset src, bitset_bindex bitno) +{ + bitset_bindex val; + bitset_bindex next = bitno; + + if (!bitset_list_reverse (src, &val, 1, &next)) + return BITSET_BINDEX_MAX; + return val; +} + + +/* Find first set bit. */ +bitset_bindex +bitset_first (bitset src) +{ + return bitset_next (src, 0); +} + + +/* Find last set bit. */ +bitset_bindex +bitset_last (bitset src) +{ + return bitset_prev (src, 0); +} + + +/* Is BITNO in SRC the only set bit? */ +bool +bitset_only_set_p (bitset src, bitset_bindex bitno) +{ + bitset_bindex val[2]; + bitset_bindex next = 0; + + if (bitset_list (src, val, 2, &next) != 1) + return false; + return val[0] == bitno; +} + + +/* Print contents of bitset BSET to FILE. */ +static void +bitset_print (FILE *file, bitset bset, bool verbose) +{ + unsigned int pos; + bitset_bindex i; + bitset_iterator iter; + + if (verbose) + fprintf (file, "n_bits = %lu, set = {", + (unsigned long int) bitset_size (bset)); + + pos = 30; + BITSET_FOR_EACH (iter, bset, i, 0) + { + if (pos > 70) + { + fprintf (file, "\n"); + pos = 0; + } + + fprintf (file, "%lu ", (unsigned long int) i); + pos += 1 + (i >= 10) + (i >= 100); + }; + + if (verbose) + fprintf (file, "}\n"); +} + + +/* Dump bitset BSET to FILE. */ +void +bitset_dump (FILE *file, bitset bset) +{ + bitset_print (file, bset, false); +} + + +/* Release memory associated with bitsets. */ +void +bitset_release_memory (void) +{ + lbitset_release_memory (); + ebitset_release_memory (); +} + + +/* Toggle bit BITNO in bitset BSET and the new value of the bit. */ +bool +bitset_toggle_ (bitset bset, bitset_bindex bitno) +{ + /* This routine is for completeness. It could be optimized if + required. */ + if (bitset_test (bset, bitno)) + { + bitset_reset (bset, bitno); + return false; + } + else + { + bitset_set (bset, bitno); + return true; + } +} + + +/* Return number of bits in bitset SRC. */ +bitset_bindex +bitset_size_ (bitset src) +{ + return BITSET_NBITS_ (src); +} + + +/* Return number of bits set in bitset SRC. */ +bitset_bindex +bitset_count_ (bitset src) +{ + bitset_bindex list[BITSET_LIST_SIZE]; + bitset_bindex next; + bitset_bindex num; + bitset_bindex count; + + /* This could be greatly sped up by adding a count method for each + bitset implementation that uses a direct technique (based on + masks) for counting the number of bits set in a word. */ + + next = 0; + for (count = 0; (num = bitset_list (src, list, BITSET_LIST_SIZE, &next)); + count += num) + continue; + + return count; +} + + +/* DST = SRC. Return true if DST != SRC. + This is a fallback for the case where SRC and DST are different + bitset types. */ +bool +bitset_copy_ (bitset dst, bitset src) +{ + bitset_bindex i; + bitset_iterator iter; + + /* Convert bitset types. We assume that the DST bitset + is large enough to hold the SRC bitset. */ + bitset_zero (dst); + BITSET_FOR_EACH (iter, src, i, 0) + { + bitset_set (dst, i); + }; + + return true; +} + + +/* This is a fallback for implementations that do not support + four operand operations. */ +static inline bool +bitset_op4_cmp (bitset dst, bitset src1, bitset src2, bitset src3, + enum bitset_ops op) +{ + bool changed = false; + bool stats_enabled_save; + bitset tmp; + + /* Create temporary bitset. */ + stats_enabled_save = bitset_stats_enabled; + bitset_stats_enabled = false; + tmp = bitset_alloc (0, bitset_type_get (dst)); + bitset_stats_enabled = stats_enabled_save; + + switch (op) + { + default: + abort (); + + case BITSET_OP_OR_AND: + bitset_or (tmp, src1, src2); + changed = bitset_and_cmp (dst, src3, tmp); + break; + + case BITSET_OP_AND_OR: + bitset_and (tmp, src1, src2); + changed = bitset_or_cmp (dst, src3, tmp); + break; + + case BITSET_OP_ANDN_OR: + bitset_andn (tmp, src1, src2); + changed = bitset_or_cmp (dst, src3, tmp); + break; + } + + bitset_free (tmp); + return changed; +} + + +/* DST = (SRC1 & SRC2) | SRC3. */ +void +bitset_and_or_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_and_or_cmp_ (dst, src1, src2, src3); +} + + +/* DST = (SRC1 & SRC2) | SRC3. Return non-zero if + DST != (SRC1 & SRC2) | SRC3. */ +bool +bitset_and_or_cmp_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + return bitset_op4_cmp (dst, src1, src2, src3, BITSET_OP_AND_OR); +} + + +/* DST = (SRC1 & ~SRC2) | SRC3. */ +void +bitset_andn_or_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_andn_or_cmp_ (dst, src1, src2, src3); +} + + +/* DST = (SRC1 & ~SRC2) | SRC3. Return non-zero if + DST != (SRC1 & ~SRC2) | SRC3. */ +bool +bitset_andn_or_cmp_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + return bitset_op4_cmp (dst, src1, src2, src3, BITSET_OP_ANDN_OR); +} + + +/* DST = (SRC1 | SRC2) & SRC3. */ +void +bitset_or_and_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + bitset_or_and_cmp_ (dst, src1, src2, src3); +} + + +/* DST = (SRC1 | SRC2) & SRC3. Return non-zero if + DST != (SRC1 | SRC2) & SRC3. */ +bool +bitset_or_and_cmp_ (bitset dst, bitset src1, bitset src2, bitset src3) +{ + return bitset_op4_cmp (dst, src1, src2, src3, BITSET_OP_OR_AND); +} + + +/* Function to be called from debugger to print bitset. */ +void +debug_bitset (bitset bset) +{ + if (bset) + bitset_print (stderr, bset, true); +} diff --git a/lib/bitset.h b/lib/bitset.h new file mode 100644 index 00000000..45c8818c --- /dev/null +++ b/lib/bitset.h @@ -0,0 +1,392 @@ +/* Generic bitsets. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BITSET_H +#define _BITSET_H + +/* This file is the public interface to the bitset abstract data type. + Only use the functions and macros defined in this file. */ + +#include "bbitset.h" +#include "obstack.h" +#include <stdio.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +/* Attributes used to select a bitset implementation. */ +enum bitset_attr {BITSET_FIXED = 1, /* Bitset size fixed. */ + BITSET_VARIABLE = 2, /* Bitset size variable. */ + BITSET_DENSE = 4, /* Bitset dense. */ + BITSET_SPARSE = 8, /* Bitset sparse. */ + BITSET_FRUGAL = 16, /* Prefer most compact. */ + BITSET_GREEDY = 32}; /* Prefer fastest at memory expense. */ + +typedef unsigned int bitset_attrs; + +/* The contents of the union should be considered to be private. + While I would like to make this union opaque, it needs to be + visible for the inline bit set/test functions, and for delegation + to the proper implementation. */ +union bitset_union +{ + /* This must be the first member of every other structure that is a + member of this union. */ + struct bbitset_struct b; /* Base bitset data. */ + + struct abitset_struct + { + struct bbitset_struct b; + bitset_word words[1]; /* The array of bits. */ + } a; + + struct ebitset_struct + { + struct bbitset_struct b; + bitset_windex size; /* Number of elements. */ + struct ebitset_elt_struct **elts; /* Expanding array of ptrs to elts. */ + } e; + + struct lbitset_struct + { + struct bbitset_struct b; + struct lbitset_elt_struct *head; /* First element in linked list. */ + struct lbitset_elt_struct *tail; /* Last element in linked list. */ + } l; + + struct bitset_stats_struct + { + struct bbitset_struct b; + bitset bset; + } s; + + struct vbitset_struct + { + struct bbitset_struct b; + bitset_windex size; /* Allocated size of array. */ + } v; + +}; + + +/* The contents of this structure should be considered private. + It is used for iterating over set bits. */ +typedef struct +{ + bitset_bindex list[BITSET_LIST_SIZE]; + bitset_bindex next; + bitset_bindex num; + bitset_bindex i; +} bitset_iterator; + + +/* Return bytes required for bitset of desired type and size. */ +extern size_t bitset_bytes (enum bitset_type, bitset_bindex); + +/* Initialise a bitset with desired type and size. */ +extern bitset bitset_init (bitset, bitset_bindex, enum bitset_type); + +/* Select an implementation type based on the desired bitset size + and attributes. */ +extern enum bitset_type bitset_type_choose (bitset_bindex, bitset_attrs); + +/* Create a bitset of desired type and size. The bitset is zeroed. */ +extern bitset bitset_alloc (bitset_bindex, enum bitset_type); + +/* Free bitset. */ +extern void bitset_free (bitset); + +/* Create a bitset of desired type and size using an obstack. The + bitset is zeroed. */ +extern bitset bitset_obstack_alloc (struct obstack *bobstack, + bitset_bindex, enum bitset_type); + +/* Free bitset allocated on obstack. */ +extern void bitset_obstack_free (bitset); + +/* Create a bitset of desired size and attributes. The bitset is zeroed. */ +extern bitset bitset_create (bitset_bindex, bitset_attrs); + +/* Return bitset type. */ +extern enum bitset_type bitset_type_get (bitset); + +/* Return bitset type name. */ +extern const char *bitset_type_name_get (bitset); + + +/* Set bit BITNO in bitset BSET. */ +static inline void +bitset_set (bitset bset, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + bitset_windex offset = windex - bset->b.cindex; + + if (offset < bset->b.csize) + bset->b.cdata[offset] |= ((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); + else + BITSET_SET_ (bset, bitno); +} + + +/* Reset bit BITNO in bitset BSET. */ +static inline void +bitset_reset (bitset bset, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + bitset_windex offset = windex - bset->b.cindex; + + if (offset < bset->b.csize) + bset->b.cdata[offset] &= ~((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); + else + BITSET_RESET_ (bset, bitno); +} + + +/* Test bit BITNO in bitset BSET. */ +static inline bool +bitset_test (bitset bset, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + bitset_windex offset = windex - bset->b.cindex; + + if (offset < bset->b.csize) + return (bset->b.cdata[offset] >> (bitno % BITSET_WORD_BITS)) & 1; + else + return BITSET_TEST_ (bset, bitno); +} + + +/* Toggle bit BITNO in bitset BSET and return non-zero if now set. */ +#define bitset_toggle(bset, bitno) BITSET_TOGGLE_ (bset, bitno) + +/* Return size in bits of bitset SRC. */ +#define bitset_size(SRC) BITSET_SIZE_ (SRC) + +/* Change size of bitset. */ +extern void bitset_resize (bitset, bitset_bindex); + +/* Return number of bits set in bitset SRC. */ +#define bitset_count(SRC) BITSET_COUNT_ (SRC) + + +/* Return SRC == 0. */ +#define bitset_empty_p(SRC) BITSET_EMPTY_P_ (SRC) + +/* DST = ~0. */ +#define bitset_ones(DST) BITSET_ONES_ (DST) + +/* DST = 0. */ +#define bitset_zero(DST) BITSET_ZERO_ (DST) + + + +/* DST = SRC. */ +#define bitset_copy(DST, SRC) BITSET_COPY_ (DST, SRC) + +/* Return DST & SRC == 0. */ +#define bitset_disjoint_p(DST, SRC) BITSET_DISJOINT_P_ (DST, SRC) + +/* Return DST == SRC. */ +#define bitset_equal_p(DST, SRC) BITSET_EQUAL_P_ (DST, SRC) + +/* DST = ~SRC. */ +#define bitset_not(DST, SRC) BITSET_NOT_ (DST, SRC) + +/* Return DST == DST | SRC. */ +#define bitset_subset_p(DST, SRC) BITSET_SUBSET_P_ (DST, SRC) + + + +/* DST = SRC1 & SRC2. */ +#define bitset_and(DST, SRC1, SRC2) BITSET_AND_ (DST, SRC1, SRC2) + +/* DST = SRC1 & SRC2. Return non-zero if DST != SRC1 & SRC2. */ +#define bitset_and_cmp(DST, SRC1, SRC2) BITSET_AND_CMP_ (DST, SRC1, SRC2) + +/* DST = SRC1 & ~SRC2. */ +#define bitset_andn(DST, SRC1, SRC2) BITSET_ANDN_ (DST, SRC1, SRC2) + +/* DST = SRC1 & ~SRC2. Return non-zero if DST != SRC1 & ~SRC2. */ +#define bitset_andn_cmp(DST, SRC1, SRC2) BITSET_ANDN_CMP_ (DST, SRC1, SRC2) + +/* DST = SRC1 | SRC2. */ +#define bitset_or(DST, SRC1, SRC2) BITSET_OR_ (DST, SRC1, SRC2) + +/* DST = SRC1 | SRC2. Return non-zero if DST != SRC1 | SRC2. */ +#define bitset_or_cmp(DST, SRC1, SRC2) BITSET_OR_CMP_ (DST, SRC1, SRC2) + +/* DST = SRC1 ^ SRC2. */ +#define bitset_xor(DST, SRC1, SRC2) BITSET_XOR_ (DST, SRC1, SRC2) + +/* DST = SRC1 ^ SRC2. Return non-zero if DST != SRC1 ^ SRC2. */ +#define bitset_xor_cmp(DST, SRC1, SRC2) BITSET_XOR_CMP_ (DST, SRC1, SRC2) + + + +/* DST = (SRC1 & SRC2) | SRC3. */ +#define bitset_and_or(DST, SRC1, SRC2, SRC3) \ + BITSET_AND_OR_ (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 & SRC2) | SRC3. Return non-zero if + DST != (SRC1 & SRC2) | SRC3. */ +#define bitset_and_or_cmp(DST, SRC1, SRC2, SRC3) \ + BITSET_AND_OR_CMP_ (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 & ~SRC2) | SRC3. */ +#define bitset_andn_or(DST, SRC1, SRC2, SRC3) \ + BITSET_ANDN_OR_ (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 & ~SRC2) | SRC3. Return non-zero if + DST != (SRC1 & ~SRC2) | SRC3. */ +#define bitset_andn_or_cmp(DST, SRC1, SRC2, SRC3) \ + BITSET_ANDN_OR_CMP_ (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 | SRC2) & SRC3. */ +#define bitset_or_and(DST, SRC1, SRC2, SRC3)\ + BITSET_OR_AND_ (DST, SRC1, SRC2, SRC3) + +/* DST = (SRC1 | SRC2) & SRC3. Return non-zero if + DST != (SRC1 | SRC2) & SRC3. */ +#define bitset_or_and_cmp(DST, SRC1, SRC2, SRC3)\ + BITSET_OR_AND_CMP_ (DST, SRC1, SRC2, SRC3) + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT. Return with actual number of bits found and with *NEXT + indicating where search stopped. */ +#define bitset_list(BSET, LIST, NUM, NEXT) \ + BITSET_LIST_ (BSET, LIST, NUM, NEXT) + +/* Find reverse list of up to NUM bits set in BSET starting from and + including NEXT. Return with actual number of bits found and with + *NEXT indicating where search stopped. */ +#define bitset_list_reverse(BSET, LIST, NUM, NEXT) \ + BITSET_LIST_REVERSE_ (BSET, LIST, NUM, NEXT) + +/* Return true if both bitsets are of the same type and size. */ +extern bool bitset_compatible_p (bitset bset1, bitset bset2); + +/* Find next set bit from the given bit index. */ +extern bitset_bindex bitset_next (bitset, bitset_bindex); + +/* Find previous set bit from the given bit index. */ +extern bitset_bindex bitset_prev (bitset, bitset_bindex); + +/* Find first set bit. */ +extern bitset_bindex bitset_first (bitset); + +/* Find last set bit. */ +extern bitset_bindex bitset_last (bitset); + +/* Return nonzero if this is the only set bit. */ +extern bool bitset_only_set_p (bitset, bitset_bindex); + +/* Dump bitset. */ +extern void bitset_dump (FILE *, bitset); + +/* Loop over all elements of BSET, starting with MIN, setting INDEX + to the index of each set bit. For example, the following will print + the bits set in a bitset: + + bitset_bindex i; + bitset_iterator iter; + + BITSET_FOR_EACH (iter, src, i, 0) + { + printf ("%lu ", (unsigned long int) i); + }; +*/ +#define BITSET_FOR_EACH(ITER, BSET, INDEX, MIN) \ + for (ITER.next = (MIN), ITER.num = BITSET_LIST_SIZE; \ + (ITER.num == BITSET_LIST_SIZE) \ + && (ITER.num = bitset_list (BSET, ITER.list, \ + BITSET_LIST_SIZE, &ITER.next));) \ + for (ITER.i = 0; \ + ITER.i < ITER.num && ((INDEX) = ITER.list[ITER.i], 1); \ + ITER.i++) + + +/* Loop over all elements of BSET, in reverse order starting with + MIN, setting INDEX to the index of each set bit. For example, the + following will print the bits set in a bitset in reverse order: + + bitset_bindex i; + bitset_iterator iter; + + BITSET_FOR_EACH_REVERSE (iter, src, i, 0) + { + printf ("%lu ", (unsigned long int) i); + }; +*/ +#define BITSET_FOR_EACH_REVERSE(ITER, BSET, INDEX, MIN) \ + for (ITER.next = (MIN), ITER.num = BITSET_LIST_SIZE; \ + (ITER.num == BITSET_LIST_SIZE) \ + && (ITER.num = bitset_list_reverse (BSET, ITER.list, \ + BITSET_LIST_SIZE, &ITER.next));) \ + for (ITER.i = 0; \ + ITER.i < ITER.num && ((INDEX) = ITER.list[ITER.i], 1); \ + ITER.i++) + + +/* Define set operations in terms of logical operations. */ + +#define bitset_diff(DST, SRC1, SRC2) bitset_andn (DST, SRC1, SRC2) +#define bitset_diff_cmp(DST, SRC1, SRC2) bitset_andn_cmp (DST, SRC1, SRC2) + +#define bitset_intersection(DST, SRC1, SRC2) bitset_and (DST, SRC1, SRC2) +#define bitset_intersection_cmp(DST, SRC1, SRC2) bitset_and_cmp (DST, SRC1, SRC2) + +#define bitset_union(DST, SRC1, SRC2) bitset_or (DST, SRC1, SRC2) +#define bitset_union_cmp(DST, SRC1, SRC2) bitset_or_cmp (DST, SRC1, SRC2) + +/* Symmetrical difference. */ +#define bitset_symdiff(DST, SRC1, SRC2) bitset_xor (DST, SRC1, SRC2) +#define bitset_symdiff_cmp(DST, SRC1, SRC2) bitset_xor_cmp (DST, SRC1, SRC2) + +/* Union of difference. */ +#define bitset_diff_union(DST, SRC1, SRC2, SRC3) \ + bitset_andn_or (DST, SRC1, SRC2, SRC3) +#define bitset_diff_union_cmp(DST, SRC1, SRC2, SRC3) \ + bitset_andn_or_cmp (DST, SRC1, SRC2, SRC3) + + +/* Release any memory tied up with bitsets. */ +extern void bitset_release_memory (void); + +/* Enable bitset stats gathering. */ +extern void bitset_stats_enable (void); + +/* Disable bitset stats gathering. */ +extern void bitset_stats_disable (void); + +/* Read bitset stats file of accummulated stats. */ +void bitset_stats_read (const char *file_name); + +/* Write bitset stats file of accummulated stats. */ +void bitset_stats_write (const char *file_name); + +/* Dump bitset stats. */ +extern void bitset_stats_dump (FILE *); + +/* Function to debug bitset from debugger. */ +extern void debug_bitset (bitset); + +/* Function to debug bitset stats from debugger. */ +extern void debug_bitset_stats (void); + +#endif /* _BITSET_H */ diff --git a/lib/bitset_stats.c b/lib/bitset_stats.c new file mode 100644 index 00000000..7b7fb341 --- /dev/null +++ b/lib/bitset_stats.c @@ -0,0 +1,730 @@ +/* Bitset statistics. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This file is a wrapper bitset implementation for the other bitset + implementations. It provides bitset compatibility checking and + statistics gathering without having to instrument the bitset + implementations. When statistics gathering is enabled, the bitset + operations get vectored through here and we then call the appropriate + routines. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "bbitset.h" +#include "abitset.h" +#include "ebitset.h" +#include "lbitset.h" +#include "vbitset.h" +#include "bitset_stats.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "gettext.h" +#define _(Msgid) gettext (Msgid) + +/* Configuration macros. */ +#define BITSET_STATS_FILE "bitset.dat" +#define BITSET_LOG_COUNT_BINS 10 +#define BITSET_LOG_SIZE_BINS 16 +#define BITSET_DENSITY_BINS 20 + + +/* Accessor macros. */ +#define BITSET_STATS_ALLOCS_INC(TYPE) \ + bitset_stats_info->types[(TYPE)].allocs++ +#define BITSET_STATS_FREES_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].frees++ +#define BITSET_STATS_SETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].sets++ +#define BITSET_STATS_CACHE_SETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_sets++ +#define BITSET_STATS_RESETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].resets++ +#define BITSET_STATS_CACHE_RESETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_resets++ +#define BITSET_STATS_TESTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].tests++ +#define BITSET_STATS_CACHE_TESTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_tests++ +#define BITSET_STATS_LISTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].lists++ +#define BITSET_STATS_LIST_COUNTS_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_counts[(I)]++ +#define BITSET_STATS_LIST_SIZES_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_sizes[(I)]++ +#define BITSET_STATS_LIST_DENSITY_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_density[(I)]++ + + +struct bitset_type_info_struct +{ + unsigned int allocs; + unsigned int frees; + unsigned int lists; + unsigned int sets; + unsigned int cache_sets; + unsigned int resets; + unsigned int cache_resets; + unsigned int tests; + unsigned int cache_tests; + unsigned int list_counts[BITSET_LOG_COUNT_BINS]; + unsigned int list_sizes[BITSET_LOG_SIZE_BINS]; + unsigned int list_density[BITSET_DENSITY_BINS]; +}; + +struct bitset_stats_info_struct +{ + unsigned int runs; + struct bitset_type_info_struct types[BITSET_TYPE_NUM]; +}; + + +struct bitset_stats_info_struct bitset_stats_info_data; +struct bitset_stats_info_struct *bitset_stats_info; +bool bitset_stats_enabled = false; + + +/* Print a percentage histogram with message MSG to FILE. */ +static void +bitset_percent_histogram_print (FILE *file, const char *name, const char *msg, + unsigned int n_bins, unsigned int *bins) +{ + unsigned int i; + unsigned int total; + + total = 0; + for (i = 0; i < n_bins; i++) + total += bins[i]; + + if (!total) + return; + + fprintf (file, "%s %s", name, msg); + for (i = 0; i < n_bins; i++) + fprintf (file, "%.0f-%.0f%%\t%8u (%5.1f%%)\n", + i * 100.0 / n_bins, + (i + 1) * 100.0 / n_bins, bins[i], + (100.0 * bins[i]) / total); +} + + +/* Print a log histogram with message MSG to FILE. */ +static void +bitset_log_histogram_print (FILE *file, const char *name, const char *msg, + unsigned int n_bins, unsigned int *bins) +{ + unsigned int i; + unsigned int total; + unsigned int max_width; + + total = 0; + for (i = 0; i < n_bins; i++) + total += bins[i]; + + if (!total) + return; + + /* Determine number of useful bins. */ + for (i = n_bins; i > 3 && ! bins[i - 1]; i--) + continue; + n_bins = i; + + /* 2 * ceil (log10 (2) * (N - 1)) + 1. */ + max_width = 2 * (unsigned int) (0.30103 * (n_bins - 1) + 0.9999) + 1; + + fprintf (file, "%s %s", name, msg); + for (i = 0; i < 2; i++) + fprintf (file, "%*d\t%8u (%5.1f%%)\n", + max_width, i, bins[i], 100.0 * bins[i] / total); + + for (; i < n_bins; i++) + fprintf (file, "%*lu-%lu\t%8u (%5.1f%%)\n", + max_width - ((unsigned int) (0.30103 * (i) + 0.9999) + 1), + 1UL << (i - 1), + (1UL << i) - 1, + bins[i], + (100.0 * bins[i]) / total); +} + + +/* Print bitset statistics to FILE. */ +static void +bitset_stats_print_1 (FILE *file, const char *name, + struct bitset_type_info_struct *stats) +{ + if (!stats) + return; + + fprintf (file, "%s:\n", name); + fprintf (file, _("%u bitset_allocs, %u freed (%.2f%%).\n"), + stats->allocs, stats->frees, + stats->allocs ? 100.0 * stats->frees / stats->allocs : 0); + fprintf (file, _("%u bitset_sets, %u cached (%.2f%%)\n"), + stats->sets, stats->cache_sets, + stats->sets ? 100.0 * stats->cache_sets / stats->sets : 0); + fprintf (file, _("%u bitset_resets, %u cached (%.2f%%)\n"), + stats->resets, stats->cache_resets, + stats->resets ? 100.0 * stats->cache_resets / stats->resets : 0); + fprintf (file, _("%u bitset_tests, %u cached (%.2f%%)\n"), + stats->tests, stats->cache_tests, + stats->tests ? 100.0 * stats->cache_tests / stats->tests : 0); + + fprintf (file, _("%u bitset_lists\n"), stats->lists); + + bitset_log_histogram_print (file, name, _("count log histogram\n"), + BITSET_LOG_COUNT_BINS, stats->list_counts); + + bitset_log_histogram_print (file, name, _("size log histogram\n"), + BITSET_LOG_SIZE_BINS, stats->list_sizes); + + bitset_percent_histogram_print (file, name, _("density histogram\n"), + BITSET_DENSITY_BINS, stats->list_density); +} + + +/* Print all bitset statistics to FILE. */ +static void +bitset_stats_print (FILE *file, bool verbose ATTRIBUTE_UNUSED) +{ + int i; + + if (!bitset_stats_info) + return; + + fprintf (file, _("Bitset statistics:\n\n")); + + if (bitset_stats_info->runs > 1) + fprintf (file, _("Accumulated runs = %u\n"), bitset_stats_info->runs); + + for (i = 0; i < BITSET_TYPE_NUM; i++) + bitset_stats_print_1 (file, bitset_type_names[i], + &bitset_stats_info->types[i]); +} + + +/* Initialise bitset statistics logging. */ +void +bitset_stats_enable (void) +{ + if (!bitset_stats_info) + bitset_stats_info = &bitset_stats_info_data; + bitset_stats_enabled = true; +} + + +void +bitset_stats_disable (void) +{ + bitset_stats_enabled = false; +} + + +/* Read bitset statistics file. */ +void +bitset_stats_read (const char *file_name) +{ + FILE *file; + + if (!bitset_stats_info) + return; + + if (!file_name) + file_name = BITSET_STATS_FILE; + + file = fopen (file_name, "r"); + if (file) + { + if (fread (&bitset_stats_info_data, sizeof (bitset_stats_info_data), + 1, file) != 1) + { + if (ferror (file)) + perror (_("Could not read stats file.")); + else + fprintf (stderr, _("Bad stats file size.\n")); + } + if (fclose (file) != 0) + perror (_("Could not read stats file.")); + } + bitset_stats_info_data.runs++; +} + + +/* Write bitset statistics file. */ +void +bitset_stats_write (const char *file_name) +{ + FILE *file; + + if (!bitset_stats_info) + return; + + if (!file_name) + file_name = BITSET_STATS_FILE; + + file = fopen (file_name, "w"); + if (file) + { + if (fwrite (&bitset_stats_info_data, sizeof (bitset_stats_info_data), + 1, file) != 1) + perror (_("Could not write stats file.")); + if (fclose (file) != 0) + perror (_("Could not write stats file.")); + } + else + perror (_("Could not open stats file for writing.")); +} + + +/* Dump bitset statistics to FILE. */ +void +bitset_stats_dump (FILE *file) +{ + bitset_stats_print (file, false); +} + + +/* Function to be called from debugger to print bitset stats. */ +void +debug_bitset_stats (void) +{ + bitset_stats_print (stderr, true); +} + + +static void +bitset_stats_set (bitset dst, bitset_bindex bitno) +{ + bitset bset = dst->s.bset; + bitset_windex wordno = bitno / BITSET_WORD_BITS; + bitset_windex offset = wordno - bset->b.cindex; + + BITSET_STATS_SETS_INC (bset); + + if (offset < bset->b.csize) + { + bset->b.cdata[offset] |= (bitset_word) 1 << (bitno % BITSET_WORD_BITS); + BITSET_STATS_CACHE_SETS_INC (bset); + } + else + BITSET_SET_ (bset, bitno); +} + + +static void +bitset_stats_reset (bitset dst, bitset_bindex bitno) +{ + bitset bset = dst->s.bset; + bitset_windex wordno = bitno / BITSET_WORD_BITS; + bitset_windex offset = wordno - bset->b.cindex; + + BITSET_STATS_RESETS_INC (bset); + + if (offset < bset->b.csize) + { + bset->b.cdata[offset] &= + ~((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); + BITSET_STATS_CACHE_RESETS_INC (bset); + } + else + BITSET_RESET_ (bset, bitno); +} + + +static bool +bitset_stats_toggle (bitset src, bitset_bindex bitno) +{ + return BITSET_TOGGLE_ (src->s.bset, bitno); +} + + +static bool +bitset_stats_test (bitset src, bitset_bindex bitno) +{ + bitset bset = src->s.bset; + bitset_windex wordno = bitno / BITSET_WORD_BITS; + bitset_windex offset = wordno - bset->b.cindex; + + BITSET_STATS_TESTS_INC (bset); + + if (offset < bset->b.csize) + { + BITSET_STATS_CACHE_TESTS_INC (bset); + return (bset->b.cdata[offset] >> (bitno % BITSET_WORD_BITS)) & 1; + } + else + return BITSET_TEST_ (bset, bitno); +} + + +static bitset_bindex +bitset_stats_resize (bitset src, bitset_bindex size) +{ + return BITSET_RESIZE_ (src->s.bset, size); +} + + +static bitset_bindex +bitset_stats_size (bitset src) +{ + return BITSET_SIZE_ (src->s.bset); +} + + +static bitset_bindex +bitset_stats_count (bitset src) +{ + return BITSET_COUNT_ (src->s.bset); +} + + +static bool +bitset_stats_empty_p (bitset dst) +{ + return BITSET_EMPTY_P_ (dst->s.bset); +} + + +static void +bitset_stats_ones (bitset dst) +{ + BITSET_ONES_ (dst->s.bset); +} + + +static void +bitset_stats_zero (bitset dst) +{ + BITSET_ZERO_ (dst->s.bset); +} + + +static void +bitset_stats_copy (bitset dst, bitset src) +{ + BITSET_CHECK2_ (dst, src); + BITSET_COPY_ (dst->s.bset, src->s.bset); +} + + +static bool +bitset_stats_disjoint_p (bitset dst, bitset src) +{ + BITSET_CHECK2_ (dst, src); + return BITSET_DISJOINT_P_ (dst->s.bset, src->s.bset); +} + + +static bool +bitset_stats_equal_p (bitset dst, bitset src) +{ + BITSET_CHECK2_ (dst, src); + return BITSET_EQUAL_P_ (dst->s.bset, src->s.bset); +} + + +static void +bitset_stats_not (bitset dst, bitset src) +{ + BITSET_CHECK2_ (dst, src); + BITSET_NOT_ (dst->s.bset, src->s.bset); +} + + +static bool +bitset_stats_subset_p (bitset dst, bitset src) +{ + BITSET_CHECK2_ (dst, src); + return BITSET_SUBSET_P_ (dst->s.bset, src->s.bset); +} + + +static void +bitset_stats_and (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + BITSET_AND_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static bool +bitset_stats_and_cmp (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + return BITSET_AND_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static void +bitset_stats_andn (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + BITSET_ANDN_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static bool +bitset_stats_andn_cmp (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + return BITSET_ANDN_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static void +bitset_stats_or (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + BITSET_OR_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static bool +bitset_stats_or_cmp (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + return BITSET_OR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static void +bitset_stats_xor (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + BITSET_XOR_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static bool +bitset_stats_xor_cmp (bitset dst, bitset src1, bitset src2) +{ + BITSET_CHECK3_ (dst, src1, src2); + return BITSET_XOR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); +} + + +static void +bitset_stats_and_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + BITSET_AND_OR_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static bool +bitset_stats_and_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + return BITSET_AND_OR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static void +bitset_stats_andn_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + BITSET_ANDN_OR_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static bool +bitset_stats_andn_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + return BITSET_ANDN_OR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static void +bitset_stats_or_and (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + BITSET_OR_AND_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static bool +bitset_stats_or_and_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + return BITSET_OR_AND_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); +} + + +static bitset_bindex +bitset_stats_list (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex count; + bitset_bindex tmp; + bitset_bindex size; + bitset_bindex i; + enum bitset_type type; + + count = BITSET_LIST_ (bset->s.bset, list, num, next); + + type = BITSET_TYPE_ (bset->s.bset); + BITSET_STATS_LISTS_INC (bset->s.bset); + + /* Log histogram of number of set bits. */ + for (i = 0, tmp = count; tmp; tmp >>= 1, i++) + continue; + if (i >= BITSET_LOG_COUNT_BINS) + i = BITSET_LOG_COUNT_BINS - 1; + BITSET_STATS_LIST_COUNTS_INC (bset->s.bset, i); + + /* Log histogram of number of bits in set. */ + size = BITSET_SIZE_ (bset->s.bset); + for (i = 0, tmp = size; tmp; tmp >>= 1, i++) + continue; + if (i >= BITSET_LOG_SIZE_BINS) + i = BITSET_LOG_SIZE_BINS - 1; + BITSET_STATS_LIST_SIZES_INC (bset->s.bset, i); + + /* Histogram of fraction of bits set. */ + i = size ? (count * BITSET_DENSITY_BINS) / size : 0; + if (i >= BITSET_DENSITY_BINS) + i = BITSET_DENSITY_BINS - 1; + BITSET_STATS_LIST_DENSITY_INC (bset->s.bset, i); + return count; +} + + +static bitset_bindex +bitset_stats_list_reverse (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + return BITSET_LIST_REVERSE_ (bset->s.bset, list, num, next); +} + + +static void +bitset_stats_free (bitset bset) +{ + BITSET_STATS_FREES_INC (bset->s.bset); + BITSET_FREE_ (bset->s.bset); +} + + +struct bitset_vtable bitset_stats_vtable = { + bitset_stats_set, + bitset_stats_reset, + bitset_stats_toggle, + bitset_stats_test, + bitset_stats_resize, + bitset_stats_size, + bitset_stats_count, + bitset_stats_empty_p, + bitset_stats_ones, + bitset_stats_zero, + bitset_stats_copy, + bitset_stats_disjoint_p, + bitset_stats_equal_p, + bitset_stats_not, + bitset_stats_subset_p, + bitset_stats_and, + bitset_stats_and_cmp, + bitset_stats_andn, + bitset_stats_andn_cmp, + bitset_stats_or, + bitset_stats_or_cmp, + bitset_stats_xor, + bitset_stats_xor_cmp, + bitset_stats_and_or, + bitset_stats_and_or_cmp, + bitset_stats_andn_or, + bitset_stats_andn_or_cmp, + bitset_stats_or_and, + bitset_stats_or_and_cmp, + bitset_stats_list, + bitset_stats_list_reverse, + bitset_stats_free, + BITSET_STATS +}; + + +/* Return enclosed bitset type. */ +enum bitset_type +bitset_stats_type_get (bitset bset) +{ + return BITSET_TYPE_ (bset->s.bset); +} + + +size_t +bitset_stats_bytes (void) +{ + return sizeof (struct bitset_stats_struct); +} + + +bitset +bitset_stats_init (bitset bset, bitset_bindex n_bits, enum bitset_type type) +{ + size_t bytes; + bitset sbset; + + bset->b.vtable = &bitset_stats_vtable; + + /* Disable cache. */ + bset->b.cindex = 0; + bset->b.csize = 0; + bset->b.cdata = 0; + + BITSET_NBITS_ (bset) = n_bits; + + /* Set up the actual bitset implementation that + we are a wrapper over. */ + switch (type) + { + default: + abort (); + + case BITSET_ARRAY: + bytes = abitset_bytes (n_bits); + sbset = xcalloc (1, bytes); + abitset_init (sbset, n_bits); + break; + + case BITSET_LIST: + bytes = lbitset_bytes (n_bits); + sbset = xcalloc (1, bytes); + lbitset_init (sbset, n_bits); + break; + + case BITSET_TABLE: + bytes = ebitset_bytes (n_bits); + sbset = xcalloc (1, bytes); + ebitset_init (sbset, n_bits); + break; + + case BITSET_VARRAY: + bytes = vbitset_bytes (n_bits); + sbset = xcalloc (1, bytes); + vbitset_init (sbset, n_bits); + break; + } + + bset->s.bset = sbset; + + BITSET_STATS_ALLOCS_INC (type); + + return bset; +} diff --git a/lib/bitset_stats.h b/lib/bitset_stats.h new file mode 100644 index 00000000..6378c5ca --- /dev/null +++ b/lib/bitset_stats.h @@ -0,0 +1,32 @@ +/* Functions to support bitset statistics. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BITSET_STATS_H +#define _BITSET_STATS_H + +#include "bbitset.h" + +extern bool bitset_stats_enabled; + +extern enum bitset_type bitset_stats_type_get (bitset); + +extern size_t bitset_stats_bytes (void); + +extern bitset bitset_stats_init (bitset, bitset_bindex, enum bitset_type); + +#endif diff --git a/lib/bitsetv-print.c b/lib/bitsetv-print.c new file mode 100644 index 00000000..00838713 --- /dev/null +++ b/lib/bitsetv-print.c @@ -0,0 +1,71 @@ +/* Bitset vectors. + Copyright (C) 2001, 2002, 2004, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include "bitsetv-print.h" + +/*--------------------------------------------------------. +| Display the MATRIX array of SIZE bitsets of size SIZE. | +`--------------------------------------------------------*/ + +void +bitsetv_matrix_dump (FILE * out, const char *title, bitsetv bset) +{ + bitset_bindex i, j; + bitset_bindex hsize = bitset_size (bset[0]); + + /* Title. */ + fprintf (out, "%s BEGIN\n", title); + + /* Column numbers. */ + fputs (" ", out); + for (i = 0; i < hsize; ++i) + putc (i / 10 ? '0' + i / 10 : ' ', out); + putc ('\n', out); + fputs (" ", out); + for (i = 0; i < hsize; ++i) + fprintf (out, "%d", (int) (i % 10)); + putc ('\n', out); + + /* Bar. */ + fputs (" .", out); + for (i = 0; i < hsize; ++i) + putc ('-', out); + fputs (".\n", out); + + /* Contents. */ + for (i = 0; bset[i]; ++i) + { + fprintf (out, "%2lu|", (unsigned long int) i); + for (j = 0; j < hsize; ++j) + fputs (bitset_test (bset[i], j) ? "1" : " ", out); + fputs ("|\n", out); + } + + /* Bar. */ + fputs (" `", out); + for (i = 0; i < hsize; ++i) + putc ('-', out); + fputs ("'\n", out); + + /* End title. */ + fprintf (out, "%s END\n\n", title); +} diff --git a/lib/bitsetv-print.h b/lib/bitsetv-print.h new file mode 100644 index 00000000..e54be683 --- /dev/null +++ b/lib/bitsetv-print.h @@ -0,0 +1,27 @@ +/* Bitset vectors. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Akim Demaille (akim@freefriends.org). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BITSETV_PRINT_H +#define _BITSETV_PRINT_H + +#include "bitsetv.h" + +/* Dump vector of bitsets as a matrix. */ +extern void bitsetv_matrix_dump (FILE *, const char *, bitsetv); + +#endif /* _BITSETV_H */ diff --git a/lib/bitsetv.c b/lib/bitsetv.c new file mode 100644 index 00000000..ae79853c --- /dev/null +++ b/lib/bitsetv.c @@ -0,0 +1,169 @@ +/* Bitset vectors. + Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include "bitsetv.h" + + +/* Create a vector of N_VECS bitsets, each of N_BITS, and of + type TYPE. */ +bitset * +bitsetv_alloc (bitset_bindex n_vecs, bitset_bindex n_bits, + enum bitset_type type) +{ + size_t vector_bytes; + size_t bytes; + bitset *bsetv; + bitset_bindex i; + + /* Determine number of bytes for each set. */ + bytes = bitset_bytes (type, n_bits); + + /* If size calculation overflows, memory is exhausted. */ + if (BITSET_SIZE_MAX / (sizeof (bitset) + bytes) <= n_vecs) + xalloc_die (); + + /* Allocate vector table at head of bitset array. */ + vector_bytes = (n_vecs + 1) * sizeof (bitset) + bytes - 1; + vector_bytes -= vector_bytes % bytes; + bsetv = xcalloc (1, vector_bytes + bytes * n_vecs); + + for (i = 0; i < n_vecs; i++) + { + bsetv[i] = (bitset) (void *) ((char *) bsetv + vector_bytes + i * bytes); + + bitset_init (bsetv[i], n_bits, type); + } + + /* Null terminate table. */ + bsetv[i] = 0; + return bsetv; +} + + +/* Create a vector of N_VECS bitsets, each of N_BITS, and with + attribute hints specified by ATTR. */ +bitset * +bitsetv_create (bitset_bindex n_vecs, bitset_bindex n_bits, unsigned int attr) +{ + enum bitset_type type; + + type = bitset_type_choose (n_bits, attr); + return bitsetv_alloc (n_vecs, n_bits, type); +} + + +/* Free bitset vector BSETV. */ +void +bitsetv_free (bitsetv bsetv) +{ + bitset_bindex i; + + for (i = 0; bsetv[i]; i++) + BITSET_FREE_ (bsetv[i]); + free (bsetv); +} + + +/* Zero a vector of bitsets. */ +void +bitsetv_zero (bitsetv bsetv) +{ + bitset_bindex i; + + for (i = 0; bsetv[i]; i++) + bitset_zero (bsetv[i]); +} + + +/* Set a vector of bitsets to ones. */ +void +bitsetv_ones (bitsetv bsetv) +{ + bitset_bindex i; + + for (i = 0; bsetv[i]; i++) + bitset_ones (bsetv[i]); +} + + +/* Given a vector BSETV of N bitsets of size N, modify its contents to + be the transitive closure of what was given. */ +void +bitsetv_transitive_closure (bitsetv bsetv) +{ + bitset_bindex i; + bitset_bindex j; + + for (i = 0; bsetv[i]; i++) + for (j = 0; bsetv[j]; j++) + if (bitset_test (bsetv[j], i)) + bitset_or (bsetv[j], bsetv[j], bsetv[i]); +} + + +/* Given a vector BSETV of N bitsets of size N, modify its contents to + be the reflexive transitive closure of what was given. This is + the same as transitive closure but with all bits on the diagonal + of the bit matrix set. */ +void +bitsetv_reflexive_transitive_closure (bitsetv bsetv) +{ + bitset_bindex i; + + bitsetv_transitive_closure (bsetv); + for (i = 0; bsetv[i]; i++) + bitset_set (bsetv[i], i); +} + + +/* Dump the contents of a bitset vector BSETV with N_VECS elements to + FILE. */ +void +bitsetv_dump (FILE *file, char const *title, char const *subtitle, + bitsetv bsetv) +{ + bitset_windex i; + + fprintf (file, "%s\n", title); + for (i = 0; bsetv[i]; i++) + { + fprintf (file, "%s %lu\n", subtitle, (unsigned long int) i); + bitset_dump (file, bsetv[i]); + } + + fprintf (file, "\n"); +} + + +void +debug_bitsetv (bitsetv bsetv) +{ + bitset_windex i; + + for (i = 0; bsetv[i]; i++) + { + fprintf (stderr, "%lu: ", (unsigned long int) i); + debug_bitset (bsetv[i]); + } + + fprintf (stderr, "\n"); +} diff --git a/lib/bitsetv.h b/lib/bitsetv.h new file mode 100644 index 00000000..652f9e39 --- /dev/null +++ b/lib/bitsetv.h @@ -0,0 +1,59 @@ +/* Bitset vectors. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _BITSETV_H +#define _BITSETV_H + +#include "bitset.h" + +typedef bitset * bitsetv; + +/* Create a vector of N_VECS bitsets, each of N_BITS, and of + type TYPE. */ +extern bitsetv bitsetv_alloc (bitset_bindex, bitset_bindex, enum bitset_type); + +/* Create a vector of N_VECS bitsets, each of N_BITS, and with + attribute hints specified by ATTR. */ +extern bitsetv bitsetv_create (bitset_bindex, bitset_bindex, unsigned int); + +/* Free vector of bitsets. */ +extern void bitsetv_free (bitsetv); + +/* Zero vector of bitsets. */ +extern void bitsetv_zero (bitsetv); + +/* Set vector of bitsets. */ +extern void bitsetv_ones (bitsetv); + +/* Given a vector BSETV of N bitsets of size N, modify its contents to + be the transitive closure of what was given. */ +extern void bitsetv_transitive_closure (bitsetv); + +/* Given a vector BSETV of N bitsets of size N, modify its contents to + be the reflexive transitive closure of what was given. This is + the same as transitive closure but with all bits on the diagonal + of the bit matrix set. */ +extern void bitsetv_reflexive_transitive_closure (bitsetv); + +/* Dump vector of bitsets. */ +extern void bitsetv_dump (FILE *, const char *, const char *, bitsetv); + +/* Function to debug vector of bitsets from debugger. */ +extern void debug_bitsetv (bitsetv); + +#endif /* _BITSETV_H */ diff --git a/lib/dirname.c b/lib/dirname.c new file mode 100644 index 00000000..e2b9d648 --- /dev/null +++ b/lib/dirname.c @@ -0,0 +1,121 @@ +/* dirname.c -- return all but the last element in a file name + + Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" + +#include <string.h> +#include "xalloc.h" + +/* Return the length of `dirname (FILE)', or zero if FILE is + in the working directory. Works properly even if + there are trailing slashes (by effectively ignoring them). */ +size_t +dir_len (char const *file) +{ + size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file); + size_t length; + + /* Strip the basename and any redundant slashes before it. */ + for (length = base_name (file) - file; prefix_length < length; length--) + if (! ISSLASH (file[length - 1])) + return length; + + /* But don't strip the only slash from "/". */ + return prefix_length + ISSLASH (file[prefix_length]); +} + +/* Return the leading directories part of FILE, + allocated with xmalloc. + Works properly even if there are trailing slashes + (by effectively ignoring them). */ + +char * +dir_name (char const *file) +{ + size_t length = dir_len (file); + bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (file)); + char *dir = xmalloc (length + append_dot + 1); + memcpy (dir, file, length); + if (append_dot) + dir[length++] = '.'; + dir[length] = 0; + return dir; +} + +#ifdef TEST_DIRNAME +/* + +Run the test like this (expect no output): + gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \ + basename.c dirname.c xmalloc.c error.c + sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out + +If it's been built on a DOS or Windows platforms, run another test like +this (again, expect no output): + sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out + +BEGIN-DATA +foo//// . +bar/foo//// bar +foo/ . +/ / +. . +a . +END-DATA + +BEGIN-DOS-DATA +c:///// c:/ +c:/ c:/ +c:/. c:/ +c:foo c:. +c:foo/bar c:foo +END-DOS-DATA + +*/ + +# define MAX_BUFF_LEN 1024 +# include <stdio.h> + +char *program_name; + +int +main (int argc, char *argv[]) +{ + char buff[MAX_BUFF_LEN + 1]; + + program_name = argv[0]; + + buff[MAX_BUFF_LEN] = 0; + while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) + { + char file[MAX_BUFF_LEN]; + char expected_result[MAX_BUFF_LEN]; + char const *result; + sscanf (buff, "%s %s", file, expected_result); + result = dir_name (file); + if (strcmp (result, expected_result)) + printf ("%s: got %s, expected %s\n", file, result, expected_result); + } + return 0; +} +#endif diff --git a/lib/dirname.h b/lib/dirname.h new file mode 100644 index 00000000..1688ae81 --- /dev/null +++ b/lib/dirname.h @@ -0,0 +1,47 @@ +/* Take file names apart into directory and base names. + + Copyright (C) 1998, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef DIRNAME_H_ +# define DIRNAME_H_ 1 + +# include <stdbool.h> +# include <stddef.h> + +# ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +# endif + +# ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +# endif + +# ifndef FILE_SYSTEM_PREFIX_LEN +# define FILE_SYSTEM_PREFIX_LEN(File_name) 0 +# endif + +# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) + +char *base_name (char const *file); +char *dir_name (char const *file); +size_t base_len (char const *file); +size_t dir_len (char const *file); + +bool strip_trailing_slashes (char *file); + +#endif /* not DIRNAME_H_ */ diff --git a/lib/dup-safer.c b/lib/dup-safer.c new file mode 100644 index 00000000..8cbee700 --- /dev/null +++ b/lib/dup-safer.c @@ -0,0 +1,46 @@ +/* Invoke dup, but avoid some glitches. + Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "unistd-safer.h" + +#include <fcntl.h> + +#include <unistd.h> +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +/* Like dup, but do not return STDIN_FILENO, STDOUT_FILENO, or + STDERR_FILENO. */ + +int +dup_safer (int fd) +{ +#ifdef F_DUPFD + return fcntl (fd, F_DUPFD, STDERR_FILENO + 1); +#else + /* fd_safer calls us back, but eventually the recursion unwinds and + does the right thing. */ + return fd_safer (dup (fd)); +#endif +} diff --git a/lib/ebitset.c b/lib/ebitset.c new file mode 100644 index 00000000..cedf0e28 --- /dev/null +++ b/lib/ebitset.c @@ -0,0 +1,1366 @@ +/* Functions to support expandable bitsets. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ebitset.h" +#include "obstack.h" +#include <stdlib.h> +#include <string.h> + +/* This file implements expandable bitsets. These bitsets can be of + arbitrary length and are more efficient than arrays of bits for + large sparse sets. + + Empty elements are represented by a NULL pointer in the table of + element pointers. An alternative is to point to a special zero + element. Similarly, we could represent an all 1's element with + another special ones element pointer. + + Bitsets are commonly empty so we need to ensure that this special + case is fast. A zero bitset is indicated when cdata is 0. This is + conservative since cdata may be non zero and the bitset may still + be zero. + + The bitset cache can be disabled either by setting cindex to + BITSET_WINDEX_MAX or by setting csize to 0. Here + we use the former approach since cindex needs to be updated whenever + cdata is changed. +*/ + + +/* Number of words to use for each element. */ +#define EBITSET_ELT_WORDS 2 + +/* Number of bits stored in each element. */ +#define EBITSET_ELT_BITS \ + ((unsigned int) (EBITSET_ELT_WORDS * BITSET_WORD_BITS)) + +/* Ebitset element. We use an array of bits. */ +typedef struct ebitset_elt_struct +{ + union + { + bitset_word words[EBITSET_ELT_WORDS]; /* Bits that are set. */ + struct ebitset_elt_struct *next; + } + u; +} +ebitset_elt; + + +typedef ebitset_elt *ebitset_elts; + + +/* Number of elements to initially allocate. */ + +#ifndef EBITSET_INITIAL_SIZE +#define EBITSET_INITIAL_SIZE 2 +#endif + + +enum ebitset_find_mode + { EBITSET_FIND, EBITSET_CREATE, EBITSET_SUBST }; + +static ebitset_elt ebitset_zero_elts[1]; /* Elements of all zero bits. */ + +/* Obstack to allocate bitset elements from. */ +static struct obstack ebitset_obstack; +static bool ebitset_obstack_init = false; +static ebitset_elt *ebitset_free_list; /* Free list of bitset elements. */ + +#define EBITSET_N_ELTS(N) (((N) + EBITSET_ELT_BITS - 1) / EBITSET_ELT_BITS) +#define EBITSET_ELTS(BSET) ((BSET)->e.elts) +#define EBITSET_SIZE(BSET) EBITSET_N_ELTS (BITSET_NBITS_ (BSET)) +#define EBITSET_ASIZE(BSET) ((BSET)->e.size) + +#define EBITSET_NEXT(ELT) ((ELT)->u.next) +#define EBITSET_WORDS(ELT) ((ELT)->u.words) + +/* Disable bitset cache and mark BSET as being zero. */ +#define EBITSET_ZERO_SET(BSET) ((BSET)->b.cindex = BITSET_WINDEX_MAX, \ + (BSET)->b.cdata = 0) + +#define EBITSET_CACHE_DISABLE(BSET) ((BSET)->b.cindex = BITSET_WINDEX_MAX) + +/* Disable bitset cache and mark BSET as being possibly non-zero. */ +#define EBITSET_NONZERO_SET(BSET) \ + (EBITSET_CACHE_DISABLE (BSET), (BSET)->b.cdata = (bitset_word *)~0) + +/* A conservative estimate of whether the bitset is zero. + This is non-zero only if we know for sure that the bitset is zero. */ +#define EBITSET_ZERO_P(BSET) ((BSET)->b.cdata == 0) + +/* Enable cache to point to element with table index EINDEX. + The element must exist. */ +#define EBITSET_CACHE_SET(BSET, EINDEX) \ + ((BSET)->b.cindex = (EINDEX) * EBITSET_ELT_WORDS, \ + (BSET)->b.cdata = EBITSET_WORDS (EBITSET_ELTS (BSET) [EINDEX])) + +#undef min +#undef max +#define min(a, b) ((a) > (b) ? (b) : (a)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +static bitset_bindex +ebitset_resize (bitset src, bitset_bindex n_bits) +{ + bitset_windex oldsize; + bitset_windex newsize; + + if (n_bits == BITSET_NBITS_ (src)) + return n_bits; + + oldsize = EBITSET_SIZE (src); + newsize = EBITSET_N_ELTS (n_bits); + + if (oldsize < newsize) + { + bitset_windex size; + + /* The bitset needs to grow. If we already have enough memory + allocated, then just zero what we need. */ + if (newsize > EBITSET_ASIZE (src)) + { + /* We need to allocate more memory. When oldsize is + non-zero this means that we are changing the size, so + grow the bitset 25% larger than requested to reduce + number of reallocations. */ + + if (oldsize == 0) + size = newsize; + else + size = newsize + newsize / 4; + + EBITSET_ELTS (src) + = realloc (EBITSET_ELTS (src), size * sizeof (ebitset_elt *)); + EBITSET_ASIZE (src) = size; + } + + memset (EBITSET_ELTS (src) + oldsize, 0, + (newsize - oldsize) * sizeof (ebitset_elt *)); + } + else + { + /* The bitset needs to shrink. There's no point deallocating + the memory unless it is shrinking by a reasonable amount. */ + if ((oldsize - newsize) >= oldsize / 2) + { + EBITSET_ELTS (src) + = realloc (EBITSET_ELTS (src), newsize * sizeof (ebitset_elt *)); + EBITSET_ASIZE (src) = newsize; + } + + /* Need to prune any excess bits. FIXME. */ + } + + BITSET_NBITS_ (src) = n_bits; + return n_bits; +} + + +/* Allocate a ebitset element. The bits are not cleared. */ +static inline ebitset_elt * +ebitset_elt_alloc (void) +{ + ebitset_elt *elt; + + if (ebitset_free_list != 0) + { + elt = ebitset_free_list; + ebitset_free_list = EBITSET_NEXT (elt); + } + else + { + if (!ebitset_obstack_init) + { + ebitset_obstack_init = true; + + /* Let particular systems override the size of a chunk. */ + +#ifndef OBSTACK_CHUNK_SIZE +#define OBSTACK_CHUNK_SIZE 0 +#endif + + /* Let them override the alloc and free routines too. */ + +#ifndef OBSTACK_CHUNK_ALLOC +#define OBSTACK_CHUNK_ALLOC xmalloc +#endif + +#ifndef OBSTACK_CHUNK_FREE +#define OBSTACK_CHUNK_FREE free +#endif + +#if ! defined __GNUC__ || __GNUC__ < 2 +#define __alignof__(type) 0 +#endif + + obstack_specify_allocation (&ebitset_obstack, OBSTACK_CHUNK_SIZE, + __alignof__ (ebitset_elt), + OBSTACK_CHUNK_ALLOC, + OBSTACK_CHUNK_FREE); + } + + /* Perhaps we should add a number of new elements to the free + list. */ + elt = (ebitset_elt *) obstack_alloc (&ebitset_obstack, + sizeof (ebitset_elt)); + } + + return elt; +} + + +/* Allocate a ebitset element. The bits are cleared. */ +static inline ebitset_elt * +ebitset_elt_calloc (void) +{ + ebitset_elt *elt; + + elt = ebitset_elt_alloc (); + memset (EBITSET_WORDS (elt), 0, sizeof (EBITSET_WORDS (elt))); + return elt; +} + + +static inline void +ebitset_elt_free (ebitset_elt *elt) +{ + EBITSET_NEXT (elt) = ebitset_free_list; + ebitset_free_list = elt; +} + + +/* Remove element with index EINDEX from bitset BSET. */ +static inline void +ebitset_elt_remove (bitset bset, bitset_windex eindex) +{ + ebitset_elts *elts; + ebitset_elt *elt; + + elts = EBITSET_ELTS (bset); + + elt = elts[eindex]; + + elts[eindex] = 0; + ebitset_elt_free (elt); +} + + +/* Add ELT into elts at index EINDEX of bitset BSET. */ +static inline void +ebitset_elt_add (bitset bset, ebitset_elt *elt, bitset_windex eindex) +{ + ebitset_elts *elts; + + elts = EBITSET_ELTS (bset); + /* Assume that the elts entry not allocated. */ + elts[eindex] = elt; +} + + +/* Are all bits in an element zero? */ +static inline bool +ebitset_elt_zero_p (ebitset_elt *elt) +{ + int i; + + for (i = 0; i < EBITSET_ELT_WORDS; i++) + if (EBITSET_WORDS (elt)[i]) + return false; + + return true; +} + + +static ebitset_elt * +ebitset_elt_find (bitset bset, bitset_bindex bindex, + enum ebitset_find_mode mode) +{ + ebitset_elt *elt; + bitset_windex size; + bitset_windex eindex; + ebitset_elts *elts; + + eindex = bindex / EBITSET_ELT_BITS; + + elts = EBITSET_ELTS (bset); + size = EBITSET_SIZE (bset); + + if (eindex < size) + { + if ((elt = elts[eindex])) + { + if (EBITSET_WORDS (elt) == bset->b.cdata) + return elt; + + EBITSET_CACHE_SET (bset, eindex); + return elt; + } + } + + /* The element could not be found. */ + + switch (mode) + { + default: + abort (); + + case EBITSET_FIND: + return 0; + + case EBITSET_CREATE: + if (eindex >= size) + ebitset_resize (bset, bindex); + + /* Create a new element. */ + elt = ebitset_elt_calloc (); + ebitset_elt_add (bset, elt, eindex); + EBITSET_CACHE_SET (bset, eindex); + return elt; + + case EBITSET_SUBST: + return &ebitset_zero_elts[0]; + } +} + + +/* Weed out the zero elements from the elts. */ +static inline bitset_windex +ebitset_weed (bitset bset) +{ + ebitset_elts *elts; + bitset_windex j; + bitset_windex count; + + if (EBITSET_ZERO_P (bset)) + return 0; + + elts = EBITSET_ELTS (bset); + count = 0; + for (j = 0; j < EBITSET_SIZE (bset); j++) + { + ebitset_elt *elt = elts[j]; + + if (elt) + { + if (ebitset_elt_zero_p (elt)) + { + ebitset_elt_remove (bset, j); + count++; + } + } + else + count++; + } + + count = j - count; + if (!count) + { + /* All the bits are zero. We could shrink the elts. + For now just mark BSET as known to be zero. */ + EBITSET_ZERO_SET (bset); + } + else + EBITSET_NONZERO_SET (bset); + + return count; +} + + +/* Set all bits in the bitset to zero. */ +static inline void +ebitset_zero (bitset bset) +{ + ebitset_elts *elts; + bitset_windex j; + + if (EBITSET_ZERO_P (bset)) + return; + + elts = EBITSET_ELTS (bset); + for (j = 0; j < EBITSET_SIZE (bset); j++) + { + ebitset_elt *elt = elts[j]; + + if (elt) + ebitset_elt_remove (bset, j); + } + + /* All the bits are zero. We could shrink the elts. + For now just mark BSET as known to be zero. */ + EBITSET_ZERO_SET (bset); +} + + +static inline bool +ebitset_equal_p (bitset dst, bitset src) +{ + ebitset_elts *selts; + ebitset_elts *delts; + bitset_windex j; + + if (src == dst) + return true; + + ebitset_weed (dst); + ebitset_weed (src); + + if (EBITSET_SIZE (src) != EBITSET_SIZE (dst)) + return false; + + selts = EBITSET_ELTS (src); + delts = EBITSET_ELTS (dst); + + for (j = 0; j < EBITSET_SIZE (src); j++) + { + unsigned int i; + ebitset_elt *selt = selts[j]; + ebitset_elt *delt = delts[j]; + + if (!selt && !delt) + continue; + if ((selt && !delt) || (!selt && delt)) + return false; + + for (i = 0; i < EBITSET_ELT_WORDS; i++) + if (EBITSET_WORDS (selt)[i] != EBITSET_WORDS (delt)[i]) + return false; + } + return true; +} + + +/* Copy bits from bitset SRC to bitset DST. */ +static inline void +ebitset_copy_ (bitset dst, bitset src) +{ + ebitset_elts *selts; + ebitset_elts *delts; + bitset_windex j; + + if (src == dst) + return; + + ebitset_zero (dst); + + if (BITSET_NBITS_ (dst) != BITSET_NBITS_ (src)) + ebitset_resize (dst, BITSET_NBITS_ (src)); + + selts = EBITSET_ELTS (src); + delts = EBITSET_ELTS (dst); + for (j = 0; j < EBITSET_SIZE (src); j++) + { + ebitset_elt *selt = selts[j]; + + if (selt) + { + ebitset_elt *tmp; + + tmp = ebitset_elt_alloc (); + delts[j] = tmp; + memcpy (EBITSET_WORDS (tmp), EBITSET_WORDS (selt), + sizeof (EBITSET_WORDS (selt))); + } + } + EBITSET_NONZERO_SET (dst); +} + + +/* Copy bits from bitset SRC to bitset DST. Return true if + bitsets different. */ +static inline bool +ebitset_copy_cmp (bitset dst, bitset src) +{ + if (src == dst) + return false; + + if (EBITSET_ZERO_P (dst)) + { + ebitset_copy_ (dst, src); + return !EBITSET_ZERO_P (src); + } + + if (ebitset_equal_p (dst, src)) + return false; + + ebitset_copy_ (dst, src); + return true; +} + + +/* Set bit BITNO in bitset DST. */ +static void +ebitset_set (bitset dst, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + ebitset_elt_find (dst, bitno, EBITSET_CREATE); + + dst->b.cdata[windex - dst->b.cindex] |= + (bitset_word) 1 << (bitno % BITSET_WORD_BITS); +} + + +/* Reset bit BITNO in bitset DST. */ +static void +ebitset_reset (bitset dst, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + if (!ebitset_elt_find (dst, bitno, EBITSET_FIND)) + return; + + dst->b.cdata[windex - dst->b.cindex] &= + ~((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); + + /* If all the data is zero, perhaps we should remove it now... + However, there is a good chance that the element will be needed + again soon. */ +} + + +/* Test bit BITNO in bitset SRC. */ +static bool +ebitset_test (bitset src, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + return (ebitset_elt_find (src, bitno, EBITSET_FIND) + && ((src->b.cdata[windex - src->b.cindex] + >> (bitno % BITSET_WORD_BITS)) + & 1)); +} + + +static void +ebitset_free (bitset bset) +{ + ebitset_zero (bset); + free (EBITSET_ELTS (bset)); +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +ebitset_list_reverse (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex n_bits; + bitset_bindex bitno; + bitset_bindex rbitno; + unsigned int bcount; + bitset_bindex boffset; + bitset_windex windex; + bitset_windex eindex; + bitset_windex woffset; + bitset_bindex count; + bitset_windex size; + ebitset_elts *elts; + + if (EBITSET_ZERO_P (bset)) + return 0; + + size = EBITSET_SIZE (bset); + n_bits = size * EBITSET_ELT_BITS; + rbitno = *next; + + if (rbitno >= n_bits) + return 0; + + elts = EBITSET_ELTS (bset); + + bitno = n_bits - (rbitno + 1); + + windex = bitno / BITSET_WORD_BITS; + eindex = bitno / EBITSET_ELT_BITS; + woffset = windex - eindex * EBITSET_ELT_WORDS; + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + count = 0; + bcount = bitno % BITSET_WORD_BITS; + boffset = windex * BITSET_WORD_BITS; + + do + { + ebitset_elt *elt; + bitset_word *srcp; + + elt = elts[eindex]; + if (elt) + { + srcp = EBITSET_WORDS (elt); + + do + { + bitset_word word; + + word = srcp[woffset] << (BITSET_WORD_BITS - 1 - bcount); + + for (; word; bcount--) + { + if (word & BITSET_MSB) + { + list[count++] = boffset + bcount; + if (count >= num) + { + *next = n_bits - (boffset + bcount); + return count; + } + } + word <<= 1; + } + boffset -= BITSET_WORD_BITS; + bcount = BITSET_WORD_BITS - 1; + } + while (woffset--); + } + + woffset = EBITSET_ELT_WORDS - 1; + boffset = eindex * EBITSET_ELT_BITS - BITSET_WORD_BITS; + } + while (eindex--); + + *next = n_bits - (boffset + 1); + return count; +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +ebitset_list (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex bitno; + bitset_windex windex; + bitset_windex eindex; + bitset_bindex count; + bitset_windex size; + ebitset_elt *elt; + bitset_word word; + ebitset_elts *elts; + + if (EBITSET_ZERO_P (bset)) + return 0; + + bitno = *next; + count = 0; + + elts = EBITSET_ELTS (bset); + size = EBITSET_SIZE (bset); + eindex = bitno / EBITSET_ELT_BITS; + + if (bitno % EBITSET_ELT_BITS) + { + /* We need to start within an element. This is not very common. */ + + elt = elts[eindex]; + if (elt) + { + bitset_windex woffset; + bitset_word *srcp = EBITSET_WORDS (elt); + + windex = bitno / BITSET_WORD_BITS; + woffset = eindex * EBITSET_ELT_WORDS; + + for (; (windex - woffset) < EBITSET_ELT_WORDS; windex++) + { + word = srcp[windex - woffset] >> (bitno % BITSET_WORD_BITS); + + for (; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + bitno = (windex + 1) * BITSET_WORD_BITS; + } + } + + /* Skip to next element. */ + eindex++; + } + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + for (; eindex < size; eindex++) + { + int i; + bitset_word *srcp; + + elt = elts[eindex]; + if (!elt) + continue; + + srcp = EBITSET_WORDS (elt); + windex = eindex * EBITSET_ELT_WORDS; + + if ((count + EBITSET_ELT_BITS) < num) + { + /* The coast is clear, plant boot! */ + +#if EBITSET_ELT_WORDS == 2 + word = srcp[0]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + if (!(word & 0xff)) + { + word >>= 8; + bitno += 8; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + windex++; + bitno = windex * BITSET_WORD_BITS; + + word = srcp[1]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + windex++; + bitno = windex * BITSET_WORD_BITS; +#else + for (i = 0; i < EBITSET_ELT_WORDS; i++, windex++) + { + bitno = windex * BITSET_WORD_BITS; + + word = srcp[i]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + if (!(word & 0xff)) + { + word >>= 8; + bitno += 8; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + } +#endif + } + else + { + /* Tread more carefully since we need to check + if array overflows. */ + + for (i = 0; i < EBITSET_ELT_WORDS; i++, windex++) + { + bitno = windex * BITSET_WORD_BITS; + + for (word = srcp[i]; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + } + } + } + + *next = bitno; + return count; +} + + +/* Ensure that any unused bits within the last element are clear. */ +static inline void +ebitset_unused_clear (bitset dst) +{ + unsigned int last_bit; + bitset_bindex n_bits; + + n_bits = BITSET_NBITS_ (dst); + last_bit = n_bits % EBITSET_ELT_BITS; + + if (last_bit) + { + bitset_windex eindex; + ebitset_elts *elts; + ebitset_elt *elt; + + elts = EBITSET_ELTS (dst); + + eindex = n_bits / EBITSET_ELT_BITS; + + elt = elts[eindex]; + if (elt) + { + bitset_windex windex; + bitset_windex woffset; + bitset_word *srcp = EBITSET_WORDS (elt); + + windex = n_bits / BITSET_WORD_BITS; + woffset = eindex * EBITSET_ELT_WORDS; + + srcp[windex - woffset] &= ((bitset_word) 1 << last_bit) - 1; + windex++; + for (; (windex - woffset) < EBITSET_ELT_WORDS; windex++) + srcp[windex - woffset] = 0; + } + } +} + + +static void +ebitset_ones (bitset dst) +{ + bitset_windex j; + ebitset_elt *elt; + + for (j = 0; j < EBITSET_SIZE (dst); j++) + { + /* Create new elements if they cannot be found. Perhaps + we should just add pointers to a ones element? */ + elt = + ebitset_elt_find (dst, j * EBITSET_ELT_BITS, EBITSET_CREATE); + memset (EBITSET_WORDS (elt), -1, sizeof (EBITSET_WORDS (elt))); + } + EBITSET_NONZERO_SET (dst); + ebitset_unused_clear (dst); +} + + +static bool +ebitset_empty_p (bitset dst) +{ + ebitset_elts *elts; + bitset_windex j; + + if (EBITSET_ZERO_P (dst)) + return 1; + + elts = EBITSET_ELTS (dst); + for (j = 0; j < EBITSET_SIZE (dst); j++) + { + ebitset_elt *elt = elts[j]; + + if (elt) + { + if (!ebitset_elt_zero_p (elt)) + return 0; + /* Do some weeding as we go. */ + ebitset_elt_remove (dst, j); + } + } + + /* All the bits are zero. We could shrink the elts. + For now just mark DST as known to be zero. */ + EBITSET_ZERO_SET (dst); + return 1; +} + + +static void +ebitset_not (bitset dst, bitset src) +{ + unsigned int i; + ebitset_elt *selt; + ebitset_elt *delt; + bitset_windex j; + + ebitset_resize (dst, BITSET_NBITS_ (src)); + + for (j = 0; j < EBITSET_SIZE (src); j++) + { + /* Create new elements for dst if they cannot be found + or substitute zero elements if src elements not found. */ + selt = + ebitset_elt_find (dst, j * EBITSET_ELT_BITS, EBITSET_SUBST); + delt = + ebitset_elt_find (dst, j * EBITSET_ELT_BITS, EBITSET_CREATE); + + for (i = 0; i < EBITSET_ELT_WORDS; i++) + EBITSET_WORDS (delt)[i] = ~EBITSET_WORDS (selt)[i]; + } + EBITSET_NONZERO_SET (dst); + ebitset_unused_clear (dst); +} + + +/* Is DST == DST | SRC? */ +static bool +ebitset_subset_p (bitset dst, bitset src) +{ + bitset_windex j; + ebitset_elts *selts; + ebitset_elts *delts; + bitset_windex ssize; + bitset_windex dsize; + + selts = EBITSET_ELTS (src); + delts = EBITSET_ELTS (dst); + + ssize = EBITSET_SIZE (src); + dsize = EBITSET_SIZE (dst); + + for (j = 0; j < ssize; j++) + { + unsigned int i; + ebitset_elt *selt; + ebitset_elt *delt; + + selt = j < ssize ? selts[j] : 0; + delt = j < dsize ? delts[j] : 0; + + if (!selt && !delt) + continue; + + if (!selt) + selt = &ebitset_zero_elts[0]; + if (!delt) + delt = &ebitset_zero_elts[0]; + + for (i = 0; i < EBITSET_ELT_WORDS; i++) + if (EBITSET_WORDS (delt)[i] + != (EBITSET_WORDS (selt)[i] | EBITSET_WORDS (delt)[i])) + return false; + } + return true; +} + + +/* Is DST & SRC == 0? */ +static bool +ebitset_disjoint_p (bitset dst, bitset src) +{ + bitset_windex j; + ebitset_elts *selts; + ebitset_elts *delts; + bitset_windex ssize; + bitset_windex dsize; + + selts = EBITSET_ELTS (src); + delts = EBITSET_ELTS (dst); + + ssize = EBITSET_SIZE (src); + dsize = EBITSET_SIZE (dst); + + for (j = 0; j < ssize; j++) + { + unsigned int i; + ebitset_elt *selt; + ebitset_elt *delt; + + selt = j < ssize ? selts[j] : 0; + delt = j < dsize ? delts[j] : 0; + + if (!selt || !delt) + continue; + + for (i = 0; i < EBITSET_ELT_WORDS; i++) + if ((EBITSET_WORDS (selt)[i] & EBITSET_WORDS (delt)[i])) + return false; + } + return true; +} + + + +static bool +ebitset_op3_cmp (bitset dst, bitset src1, bitset src2, enum bitset_ops op) +{ + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + bitset_windex size; + ebitset_elts *selts1; + ebitset_elts *selts2; + ebitset_elts *delts; + bitset_word *srcp1; + bitset_word *srcp2; + bitset_word *dstp; + bool changed = false; + unsigned int i; + bitset_windex j; + + ebitset_resize (dst, max (BITSET_NBITS_ (src1), BITSET_NBITS_ (src2))); + + ssize1 = EBITSET_SIZE (src1); + ssize2 = EBITSET_SIZE (src2); + dsize = EBITSET_SIZE (dst); + size = ssize1; + if (size < ssize2) + size = ssize2; + + selts1 = EBITSET_ELTS (src1); + selts2 = EBITSET_ELTS (src2); + delts = EBITSET_ELTS (dst); + + for (j = 0; j < size; j++) + { + ebitset_elt *selt1; + ebitset_elt *selt2; + ebitset_elt *delt; + + selt1 = j < ssize1 ? selts1[j] : 0; + selt2 = j < ssize2 ? selts2[j] : 0; + delt = j < dsize ? delts[j] : 0; + + if (!selt1 && !selt2) + { + if (delt) + { + changed = true; + ebitset_elt_remove (dst, j); + } + continue; + } + + if (!selt1) + selt1 = &ebitset_zero_elts[0]; + if (!selt2) + selt2 = &ebitset_zero_elts[0]; + if (!delt) + delt = ebitset_elt_calloc (); + else + delts[j] = 0; + + srcp1 = EBITSET_WORDS (selt1); + srcp2 = EBITSET_WORDS (selt2); + dstp = EBITSET_WORDS (delt); + switch (op) + { + default: + abort (); + + case BITSET_OP_OR: + for (i = 0; i < EBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ | *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_AND: + for (i = 0; i < EBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ & *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_XOR: + for (i = 0; i < EBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ ^ *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_ANDN: + for (i = 0; i < EBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ & ~(*srcp2++); + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + } + + if (!ebitset_elt_zero_p (delt)) + { + ebitset_elt_add (dst, delt, j); + } + else + { + ebitset_elt_free (delt); + } + } + + /* If we have elements of DST left over, free them all. */ + for (; j < dsize; j++) + { + ebitset_elt *delt; + + changed = true; + + delt = delts[j]; + + if (delt) + ebitset_elt_remove (dst, j); + } + + EBITSET_NONZERO_SET (dst); + return changed; +} + + +static bool +ebitset_and_cmp (bitset dst, bitset src1, bitset src2) +{ + bool changed; + + if (EBITSET_ZERO_P (src2)) + { + ebitset_weed (dst); + changed = EBITSET_ZERO_P (dst); + ebitset_zero (dst); + return changed; + } + else if (EBITSET_ZERO_P (src1)) + { + ebitset_weed (dst); + changed = EBITSET_ZERO_P (dst); + ebitset_zero (dst); + return changed; + } + return ebitset_op3_cmp (dst, src1, src2, BITSET_OP_AND); +} + + +static void +ebitset_and (bitset dst, bitset src1, bitset src2) +{ + ebitset_and_cmp (dst, src1, src2); +} + + +static bool +ebitset_andn_cmp (bitset dst, bitset src1, bitset src2) +{ + bool changed; + + if (EBITSET_ZERO_P (src2)) + { + return ebitset_copy_cmp (dst, src1); + } + else if (EBITSET_ZERO_P (src1)) + { + ebitset_weed (dst); + changed = EBITSET_ZERO_P (dst); + ebitset_zero (dst); + return changed; + } + return ebitset_op3_cmp (dst, src1, src2, BITSET_OP_ANDN); +} + + +static void +ebitset_andn (bitset dst, bitset src1, bitset src2) +{ + ebitset_andn_cmp (dst, src1, src2); +} + + +static bool +ebitset_or_cmp (bitset dst, bitset src1, bitset src2) +{ + if (EBITSET_ZERO_P (src2)) + { + return ebitset_copy_cmp (dst, src1); + } + else if (EBITSET_ZERO_P (src1)) + { + return ebitset_copy_cmp (dst, src2); + } + return ebitset_op3_cmp (dst, src1, src2, BITSET_OP_OR); +} + + +static void +ebitset_or (bitset dst, bitset src1, bitset src2) +{ + ebitset_or_cmp (dst, src1, src2); +} + + +static bool +ebitset_xor_cmp (bitset dst, bitset src1, bitset src2) +{ + if (EBITSET_ZERO_P (src2)) + { + return ebitset_copy_cmp (dst, src1); + } + else if (EBITSET_ZERO_P (src1)) + { + return ebitset_copy_cmp (dst, src2); + } + return ebitset_op3_cmp (dst, src1, src2, BITSET_OP_XOR); +} + + +static void +ebitset_xor (bitset dst, bitset src1, bitset src2) +{ + ebitset_xor_cmp (dst, src1, src2); +} + + +static void +ebitset_copy (bitset dst, bitset src) +{ + if (BITSET_COMPATIBLE_ (dst, src)) + ebitset_copy_ (dst, src); + else + bitset_copy_ (dst, src); +} + + +/* Vector of operations for linked-list bitsets. */ +struct bitset_vtable ebitset_vtable = { + ebitset_set, + ebitset_reset, + bitset_toggle_, + ebitset_test, + ebitset_resize, + bitset_size_, + bitset_count_, + ebitset_empty_p, + ebitset_ones, + ebitset_zero, + ebitset_copy, + ebitset_disjoint_p, + ebitset_equal_p, + ebitset_not, + ebitset_subset_p, + ebitset_and, + ebitset_and_cmp, + ebitset_andn, + ebitset_andn_cmp, + ebitset_or, + ebitset_or_cmp, + ebitset_xor, + ebitset_xor_cmp, + bitset_and_or_, + bitset_and_or_cmp_, + bitset_andn_or_, + bitset_andn_or_cmp_, + bitset_or_and_, + bitset_or_and_cmp_, + ebitset_list, + ebitset_list_reverse, + ebitset_free, + BITSET_TABLE +}; + + +/* Return size of initial structure. */ +size_t +ebitset_bytes (bitset_bindex n_bits ATTRIBUTE_UNUSED) +{ + return sizeof (struct ebitset_struct); +} + + +/* Initialize a bitset. */ + +bitset +ebitset_init (bitset bset, bitset_bindex n_bits) +{ + bitset_windex size; + + bset->b.vtable = &ebitset_vtable; + + bset->b.csize = EBITSET_ELT_WORDS; + + EBITSET_ZERO_SET (bset); + + size = n_bits ? (n_bits + EBITSET_ELT_BITS - 1) / EBITSET_ELT_BITS + : EBITSET_INITIAL_SIZE; + + EBITSET_ASIZE (bset) = 0; + EBITSET_ELTS (bset) = 0; + ebitset_resize (bset, n_bits); + + return bset; +} + + +void +ebitset_release_memory (void) +{ + ebitset_free_list = 0; + if (ebitset_obstack_init) + { + ebitset_obstack_init = false; + obstack_free (&ebitset_obstack, NULL); + } +} diff --git a/lib/ebitset.h b/lib/ebitset.h new file mode 100644 index 00000000..dc602734 --- /dev/null +++ b/lib/ebitset.h @@ -0,0 +1,30 @@ +/* Functions to support ebitsets. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _EBITSET_H +#define _EBITSET_H + +#include "bitset.h" + +extern size_t ebitset_bytes (bitset_bindex); + +extern bitset ebitset_init (bitset, bitset_bindex); + +extern void ebitset_release_memory (void); + +#endif diff --git a/lib/error.c b/lib/error.c new file mode 100644 index 00000000..45698be8 --- /dev/null +++ b/lib/error.c @@ -0,0 +1,304 @@ +/* Error handler for noninteractive utilities + Copyright (C) 1990-1998, 2000-2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "error.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if !_LIBC && ENABLE_NLS +# include "gettext.h" +#endif + +#ifdef _LIBC +# include <wchar.h> +# define mbsrtowcs __mbsrtowcs +#endif + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifndef _ +# define _(String) String +#endif + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +void (*error_print_progname) (void); + +/* This variable is incremented each time `error' is called. */ +unsigned int error_message_count; + +#ifdef _LIBC +/* In the GNU C library, there is a predefined variable for this. */ + +# define program_name program_invocation_name +# include <errno.h> +# include <libio/libioP.h> + +/* In GNU libc we want do not want to use the common name `error' directly. + Instead make it a weak alias. */ +extern void __error (int status, int errnum, const char *message, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern void __error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, + ...) + __attribute__ ((__format__ (__printf__, 5, 6)));; +# define error __error +# define error_at_line __error_at_line + +# include <libio/iolibio.h> +# define fflush(s) INTUSE(_IO_fflush) (s) +# undef putc +# define putc(c, fp) INTUSE(_IO_putc) (c, fp) + +# include <bits/libc-lock.h> + +#else /* not _LIBC */ + +# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P +# ifndef HAVE_DECL_STRERROR_R +"this configure-time declaration test was not run" +# endif +char *strerror_r (); +# endif + +# ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +# endif + +/* The calling program should define program_name and set it to the + name of the executing program. */ +extern char *program_name; + +# if HAVE_STRERROR_R || defined strerror_r +# define __strerror_r strerror_r +# endif +#endif /* not _LIBC */ + +static void +print_errno_message (int errnum) +{ + char const *s = NULL; + +#if defined HAVE_STRERROR_R || _LIBC + char errbuf[1024]; +# if STRERROR_R_CHAR_P || _LIBC + s = __strerror_r (errnum, errbuf, sizeof errbuf); +# else + if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) + s = errbuf; +# endif +#endif + +#if !_LIBC + if (! s && ! (s = strerror (errnum))) + s = _("Unknown system error"); +#endif + +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { + __fwprintf (stderr, L": %s", s); + return; + } +#endif + + fprintf (stderr, ": %s", s); +} + +static void +error_tail (int status, int errnum, const char *message, va_list args) +{ +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { +# define ALLOCA_LIMIT 2000 + size_t len = strlen (message) + 1; + const wchar_t *wmessage = L"out of memory"; + wchar_t *wbuf = (len < ALLOCA_LIMIT + ? alloca (len * sizeof *wbuf) + : len <= SIZE_MAX / sizeof *wbuf + ? malloc (len * sizeof *wbuf) + : NULL); + + if (wbuf) + { + size_t res; + mbstate_t st; + const char *tmp = message; + memset (&st, '\0', sizeof (st)); + res = mbsrtowcs (wbuf, &tmp, len, &st); + wmessage = res == (size_t) -1 ? L"???" : wbuf; + } + + __vfwprintf (stderr, wmessage, args); + if (! (len < ALLOCA_LIMIT)) + free (wbuf); + } + else +#endif + vfprintf (stderr, message, args); + va_end (args); + + ++error_message_count; + if (errnum) + print_errno_message (errnum); +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + putwc (L'\n', stderr); + else +#endif + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (status); +} + + +/* Print the program name and error message MESSAGE, which is a printf-style + format string with optional args. + If ERRNUM is nonzero, print its corresponding system error message. + Exit with status STATUS if it is nonzero. */ +void +error (int status, int errnum, const char *message, ...) +{ + va_list args; + +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#endif + fprintf (stderr, "%s: ", program_name); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif +} + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +int error_one_per_line; + +void +error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, ...) +{ + va_list args; + + if (error_one_per_line) + { + static const char *old_file_name; + static unsigned int old_line_number; + + if (old_line_number == line_number + && (file_name == old_file_name + || strcmp (old_file_name, file_name) == 0)) + /* Simply return and print nothing. */ + return; + + old_file_name = file_name; + old_line_number = line_number; + } + +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#endif + fprintf (stderr, "%s:", program_name); + } + + if (file_name != NULL) + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s:%d: ", file_name, line_number); + else +#endif + fprintf (stderr, "%s:%d: ", file_name, line_number); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif +} + +#ifdef _LIBC +/* Make the weak alias. */ +# undef error +# undef error_at_line +weak_alias (__error, error) +weak_alias (__error_at_line, error_at_line) +#endif diff --git a/lib/error.h b/lib/error.h new file mode 100644 index 00000000..e5220a2f --- /dev/null +++ b/lib/error.h @@ -0,0 +1,66 @@ +/* Declaration for error-reporting function + Copyright (C) 1995, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _ERROR_H +#define _ERROR_H 1 + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Print a message with `fprintf (stderr, FORMAT, ...)'; + if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). + If STATUS is nonzero, terminate the program with `exit (STATUS)'. */ + +extern void error (int __status, int __errnum, const char *__format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +extern void error_at_line (int __status, int __errnum, const char *__fname, + unsigned int __lineno, const char *__format, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +extern void (*error_print_progname) (void); + +/* This variable is incremented each time `error' is called. */ +extern unsigned int error_message_count; + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +extern int error_one_per_line; + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/lib/exit.h b/lib/exit.h new file mode 100644 index 00000000..9dbfb7ce --- /dev/null +++ b/lib/exit.h @@ -0,0 +1,32 @@ +/* exit() function. + Copyright (C) 1995, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _EXIT_H +#define _EXIT_H + +/* Get exit() declaration. */ +#include <stdlib.h> + +/* Some systems do not define EXIT_*, even with STDC_HEADERS. */ +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#endif /* _EXIT_H */ diff --git a/lib/exitfail.c b/lib/exitfail.c new file mode 100644 index 00000000..27d38c32 --- /dev/null +++ b/lib/exitfail.c @@ -0,0 +1,27 @@ +/* Failure exit status + + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "exitfail.h" +#include "exit.h" + +int volatile exit_failure = EXIT_FAILURE; diff --git a/lib/exitfail.h b/lib/exitfail.h new file mode 100644 index 00000000..e46cf9c1 --- /dev/null +++ b/lib/exitfail.h @@ -0,0 +1,20 @@ +/* Failure exit status + + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +extern int volatile exit_failure; diff --git a/lib/fd-safer.c b/lib/fd-safer.c new file mode 100644 index 00000000..5933bcbd --- /dev/null +++ b/lib/fd-safer.c @@ -0,0 +1,59 @@ +/* Return a safer copy of a file descriptor. + + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "unistd-safer.h" + +#include <errno.h> + +#include <unistd.h> +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +/* Return FD, unless FD would be a copy of standard input, output, or + error; in that case, return a duplicate of FD, closing FD. On + failure to duplicate, close FD, set errno, and return -1. Preserve + errno if FD is negative, so that the caller can always inspect + errno when the returned value is negative. + + This function is usefully wrapped around functions that return file + descriptors, e.g., fd_safer (open ("file", O_RDONLY)). */ + +int +fd_safer (int fd) +{ + if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) + { + int f = dup_safer (fd); + int e = errno; + close (fd); + errno = e; + fd = f; + } + + return fd; +} diff --git a/lib/fopen-safer.c b/lib/fopen-safer.c new file mode 100644 index 00000000..4f2ffa1b --- /dev/null +++ b/lib/fopen-safer.c @@ -0,0 +1,69 @@ +/* Invoke fopen, but avoid some glitches. + Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "stdio-safer.h" + +#include <errno.h> +#include <unistd.h> +#include "unistd-safer.h" + +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +/* Like fopen, but do not return stdin, stdout, or stderr. */ + +FILE * +fopen_safer (char const *file, char const *mode) +{ + FILE *fp = fopen (file, mode); + + if (fp) + { + int fd = fileno (fp); + + if (0 <= fd && fd <= STDERR_FILENO) + { + int f = dup_safer (fd); + + if (f < 0) + { + int e = errno; + fclose (fp); + errno = e; + return NULL; + } + + if (fclose (fp) != 0 + || ! (fp = fdopen (f, mode))) + { + int e = errno; + close (f); + errno = e; + return NULL; + } + } + } + + return fp; +} diff --git a/lib/get-errno.c b/lib/get-errno.c new file mode 100644 index 00000000..8e8ef582 --- /dev/null +++ b/lib/get-errno.c @@ -0,0 +1,45 @@ +/* get-errno.c - get and set errno. + + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> + +#include "get-errno.h" + +/* Get and set errno. A source file that needs to set or get errno, + but doesn't need to test for specific errno values, can use these + functions to avoid namespace pollution. For example, a file that + defines EQUAL should not include <errno.h>, since <errno.h> might + define EQUAL; such a file can include <get-errno.h> instead. */ + +int +get_errno (void) +{ + return errno; +} + +void +set_errno (int e) +{ + errno = e; +} diff --git a/lib/get-errno.h b/lib/get-errno.h new file mode 100644 index 00000000..d39a8dd6 --- /dev/null +++ b/lib/get-errno.h @@ -0,0 +1,20 @@ +/* get-errno.h - get and set errno. + + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +extern int get_errno (void); +extern void set_errno (int); diff --git a/lib/getopt.c b/lib/getopt.c new file mode 100644 index 00000000..83bd6db4 --- /dev/null +++ b/lib/getopt.c @@ -0,0 +1,1191 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "getopt.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef VMS +# include <unixlib.h> +#endif + +#ifdef _LIBC +# include <libintl.h> +#else +# include "gettext.h" +# define _(msgid) gettext (msgid) +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include <wchar.h> +#endif + +#ifndef attribute_hidden +# define attribute_hidden +#endif + +/* Unlike standard Unix `getopt', functions like `getopt_long' + let the user intersperse the options with the other arguments. + + As `getopt_long' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Using `getopt' or setting the environment variable POSIXLY_CORRECT + disables permutation. + Then the application's behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt_int.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Keep a global copy of all internal members of getopt_data. */ + +static struct _getopt_data getopt_data; + + +#if defined HAVE_DECL_GETENV && !HAVE_DECL_GETENV +extern char *getenv (); +#endif + +#ifdef _LIBC +/* Stored original parameters. + XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (d->__nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (char **argv, struct _getopt_data *d) +{ + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + d->__nonoption_flags_max_len), + '\0', top + 1 - d->__nonoption_flags_max_len); + d->__nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (int argc, char **argv, const char *optstring, + int posixly_correct, struct _getopt_data *d) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + d->__first_nonopt = d->__last_nonopt = d->optind; + + d->__nextchar = NULL; + + d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (d->__posixly_correct) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (!d->__posixly_correct + && argc == __libc_argc && argv == __libc_argv) + { + if (d->__nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + d->__nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = d->__nonoption_flags_max_len = strlen (orig_str); + if (d->__nonoption_flags_max_len < argc) + d->__nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (d->__nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + d->__nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', d->__nonoption_flags_max_len - len); + } + } + d->__nonoption_flags_len = d->__nonoption_flags_max_len; + } + else + d->__nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. + + If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT + environment variable were set. */ + +int +_getopt_internal_r (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct, struct _getopt_data *d) +{ + int print_errors = d->opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + d->optarg = NULL; + + if (d->optind == 0 || !d->__initialized) + { + if (d->optind == 0) + d->optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring, + posixly_correct, d); + d->__initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ + || (d->optind < d->__nonoption_flags_len \ + && __getopt_nonoption_flags[d->optind] == '1')) +#else +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') +#endif + + if (d->__nextchar == NULL || *d->__nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + + if (d->__ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (d->optind < argc && NONOPTION_P) + d->optind++; + d->__last_nonopt = d->optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (d->optind != argc && !strcmp (argv[d->optind], "--")) + { + d->optind++; + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + + d->optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (d->optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + d->__nextchar = (argv[d->optind] + 1 + + (longopts != NULL && argv[d->optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[d->optind][1] == '-' + || (long_only && (argv[d->optind][2] + || !strchr (optstring, argv[d->optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + d->optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf (stderr, _("\ +%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#else + fprintf (stderr, _("\ +%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + + d->__nextchar += strlen (d->__nextchar); + + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[d->optind][1] == '-' + || strchr (optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), + argv[0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], d->__nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->__nextchar = (char *) ""; + d->optind++; + d->optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *d->__nextchar++; + char *temp = strchr (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*d->__nextchar == '\0') + ++d->optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (d->__posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `d->optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; + nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + d->__nextchar += strlen (d->__nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + d->__nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + __fxprintf (NULL, "%s", buf); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} + +int +_getopt_internal (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct) +{ + int result; + + getopt_data.optind = optind; + getopt_data.opterr = opterr; + + result = _getopt_internal_r (argc, argv, optstring, longopts, longind, + long_only, posixly_correct, &getopt_data); + + optind = getopt_data.optind; + optarg = getopt_data.optarg; + optopt = getopt_data.optopt; + + return result; +} + +/* glibc gets a LSB-compliant getopt. + Standalone applications get a POSIX-compliant getopt. */ +#if _LIBC +enum { POSIXLY_CORRECT = 0 }; +#else +enum { POSIXLY_CORRECT = 1 }; +#endif + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0, + POSIXLY_CORRECT); +} + + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt1.c b/lib/getopt1.c new file mode 100644 index 00000000..25d79265 --- /dev/null +++ b/lib/getopt1.c @@ -0,0 +1,174 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# include <getopt.h> +#else +# include "getopt.h" +#endif +#include "getopt_int.h" + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 0, 0); +} + +int +_getopt_long_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 0, 0, d); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (int argc, char *__getopt_argv_const *argv, + const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 1, 0); +} + +int +_getopt_long_only_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 1, 0, d); +} + + +#ifdef TEST + +#include <stdio.h> + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt_.h b/lib/getopt_.h new file mode 100644 index 00000000..3c406e53 --- /dev/null +++ b/lib/getopt_.h @@ -0,0 +1,225 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2005 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* Standalone applications should #define __GETOPT_PREFIX to an + identifier that prefixes the external functions and variables + defined in this header. When this happens, include the + headers that might declare getopt so that they will not cause + confusion if included after this file. Then systematically rename + identifiers so that they do not collide with the system functions + and variables. Renaming avoids problems with some compilers and + linkers. */ +#if defined __GETOPT_PREFIX && !defined __need_getopt +# include <stdlib.h> +# include <stdio.h> +# include <unistd.h> +# undef __need_getopt +# undef getopt +# undef getopt_long +# undef getopt_long_only +# undef optarg +# undef opterr +# undef optind +# undef optopt +# define __GETOPT_CONCAT(x, y) x ## y +# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) +# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y) +# define getopt __GETOPT_ID (getopt) +# define getopt_long __GETOPT_ID (getopt_long) +# define getopt_long_only __GETOPT_ID (getopt_long_only) +# define optarg __GETOPT_ID (optarg) +# define opterr __GETOPT_ID (opterr) +# define optind __GETOPT_ID (optind) +# define optopt __GETOPT_ID (optopt) +#endif + +/* Standalone applications get correct prototypes for getopt_long and + getopt_long_only; they declare "char **argv". libc uses prototypes + with "char *const *argv" that are incorrect because getopt_long and + getopt_long_only can permute argv; this is required for backward + compatibility (e.g., for LSB 2.0.1). + + This used to be `#if defined __GETOPT_PREFIX && !defined __need_getopt', + but it caused redefinition warnings if both unistd.h and getopt.h were + included, since unistd.h includes getopt.h having previously defined + __need_getopt. + + The only place where __getopt_argv_const is used is in definitions + of getopt_long and getopt_long_only below, but these are visible + only if __need_getopt is not defined, so it is quite safe to rewrite + the conditional as follows: +*/ +#if !defined __need_getopt +# if defined __GETOPT_PREFIX +# define __getopt_argv_const /* empty */ +# else +# define __getopt_argv_const const +# endif +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include <features.h>, but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include <ctype.h>, which will pull in <features.h> for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include <ctype.h> +#endif + +#ifndef __THROW +# ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +# endif +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW; + +#ifndef __need_getopt +extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; +extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; + +#endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/lib/getopt_int.h b/lib/getopt_int.h new file mode 100644 index 00000000..401579fd --- /dev/null +++ b/lib/getopt_int.h @@ -0,0 +1,131 @@ +/* Internal declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _GETOPT_INT_H +#define _GETOPT_INT_H 1 + +extern int _getopt_internal (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct); + + +/* Reentrant versions which can handle parsing multiple argument + vectors at the same time. */ + +/* Data type for reentrant functions. */ +struct _getopt_data +{ + /* These have exactly the same meaning as the corresponding global + variables, except that they are used for the reentrant + versions of getopt. */ + int optind; + int opterr; + int optopt; + char *optarg; + + /* Internal members. */ + + /* True if the internal members have been initialized. */ + int __initialized; + + /* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + char *__nextchar; + + /* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters, or by calling getopt. + + PERMUTE is the default. We permute the contents of ARGV as we + scan, so that eventually all the non-options are at the end. + This allows options to be given in any order, even with programs + that were not written to expect this. + + RETURN_IN_ORDER is an option available to programs that were + written to expect options and other ARGV-elements in any order + and that care about the ordering of the two. We describe each + non-option ARGV-element as if it were the argument of an option + with character code 1. Using `-' as the first character of the + list of option characters selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + + enum + { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER + } __ordering; + + /* If the POSIXLY_CORRECT environment variable is set + or getopt was called. */ + int __posixly_correct; + + + /* Handle permutation of arguments. */ + + /* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first + of them; `last_nonopt' is the index after the last of them. */ + + int __first_nonopt; + int __last_nonopt; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + int __nonoption_flags_max_len; + int __nonoption_flags_len; +# endif +}; + +/* The initializer is necessary to set OPTIND and OPTERR to their + default values and to clear the initialization flag. */ +#define _GETOPT_DATA_INITIALIZER { 1, 1 } + +extern int _getopt_internal_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct, + struct _getopt_data *__data); + +extern int _getopt_long_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + struct _getopt_data *__data); + +extern int _getopt_long_only_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, + int *__longind, + struct _getopt_data *__data); + +#endif /* getopt_int.h */ diff --git a/lib/gettext.h b/lib/gettext.h new file mode 100644 index 00000000..285cb314 --- /dev/null +++ b/lib/gettext.h @@ -0,0 +1,78 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Many header files from the libstdc++ coming with g++ 3.3 or newer include + <libintl.h>, which chokes if dcgettext is defined as a macro. So include + it now, to make later inclusions of <libintl.h> a NOP. */ +#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include <cstdlib> +# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H +# include <libintl.h> +# endif +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/lib/gnulib.mk b/lib/gnulib.mk new file mode 100644 index 00000000..3e7b28d4 --- /dev/null +++ b/lib/gnulib.mk @@ -0,0 +1,78 @@ +# This file is generated automatically by "bootstrap". +lib_SOURCES += argmatch.h argmatch.c + +lib_SOURCES += basename.c stripslash.c + + +lib_SOURCES += exit.h + + + +BUILT_SOURCES += $(GETOPT_H) +EXTRA_DIST += getopt_.h getopt_int.h + +# We need the following in order to create <getopt.h> when the system +# doesn't have one that works with the given compiler. +getopt.h: getopt_.h + cp $(srcdir)/getopt_.h $@-t + mv $@-t $@ +MOSTLYCLEANFILES += getopt.h getopt.h-t + +# This is for those projects which use "gettextize --intl" to put a source-code +# copy of libintl into their package. In such projects, every Makefile.am needs +# -I$(top_builddir)/intl, so that <libintl.h> can be found in this directory. +# For the Makefile.ams in other directories it is the maintainer's +# responsibility; for the one from gnulib we do it here. +# This option has no effect when the user disables NLS (because then the intl +# directory contains no libintl.h file) or when the project does not use +# "gettextize --intl". +# (commented out by bootstrap) AM_CPPFLAGS += -I$(top_builddir)/intl + +lib_SOURCES += gettext.h + + + + + +lib_SOURCES += mbswidth.h mbswidth.c + + + + +BUILT_SOURCES += $(STDBOOL_H) +EXTRA_DIST += stdbool_.h + +# We need the following in order to create <stdbool.h> when the system +# doesn't have one that works. +stdbool.h: stdbool_.h + sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h > $@-t + mv $@-t $@ +MOSTLYCLEANFILES += stdbool.h stdbool.h-t + + +lib_SOURCES += stpcpy.h + + + + + + + + +BUILT_SOURCES += $(UNISTD_H) + +# We need the following in order to create an empty placeholder for +# <unistd.h> when the system doesn't have one. +unistd.h: + echo '/* Empty placeholder for $@. */' >$@ +MOSTLYCLEANFILES += unistd.h + + + +lib_SOURCES += verify.h + + +lib_SOURCES += xalloc-die.c + +lib_SOURCES += xstrndup.h xstrndup.c + diff --git a/lib/hard-locale.c b/lib/hard-locale.c new file mode 100644 index 00000000..98530fcd --- /dev/null +++ b/lib/hard-locale.c @@ -0,0 +1,75 @@ +/* hard-locale.c -- Determine whether a locale is hard. + + Copyright (C) 1997, 1998, 1999, 2002, 2003, 2004 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "hard-locale.h" + +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +#include "strdup.h" + +#ifdef __GLIBC__ +# define GLIBC_VERSION __GLIBC__ +#else +# define GLIBC_VERSION 0 +#endif + +/* Return true if the current CATEGORY locale is hard, i.e. if you + can't get away with assuming traditional C or POSIX behavior. */ +bool +hard_locale (int category) +{ + bool hard = true; + char const *p = setlocale (category, NULL); + + if (p) + { + if (2 <= GLIBC_VERSION) + { + if (strcmp (p, "C") == 0 || strcmp (p, "POSIX") == 0) + hard = false; + } + else + { + char *locale = strdup (p); + if (locale) + { + /* Temporarily set the locale to the "C" and "POSIX" locales + to find their names, so that we can determine whether one + or the other is the caller's locale. */ + if (((p = setlocale (category, "C")) + && strcmp (p, locale) == 0) + || ((p = setlocale (category, "POSIX")) + && strcmp (p, locale) == 0)) + hard = false; + + /* Restore the caller's locale. */ + setlocale (category, locale); + free (locale); + } + } + } + + return hard; +} diff --git a/lib/hard-locale.h b/lib/hard-locale.h new file mode 100644 index 00000000..c5cedc02 --- /dev/null +++ b/lib/hard-locale.h @@ -0,0 +1,26 @@ +/* Determine whether a locale is hard. + + Copyright (C) 1999, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef HARD_LOCALE_H_ +# define HARD_LOCALE_H_ 1 + +# include <stdbool.h> + +bool hard_locale (int); + +#endif /* HARD_LOCALE_H_ */ diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 00000000..f85bd519 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,1050 @@ +/* hash - hashing table processing. + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free + Software Foundation, Inc. + + Written by Jim Meyering, 1992. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* A generic hash table package. */ + +/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead + of malloc. If you change USE_OBSTACK, you have to recompile! */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "hash.h" +#include "xalloc.h" + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> + +#if USE_OBSTACK +# include "obstack.h" +# ifndef obstack_chunk_alloc +# define obstack_chunk_alloc malloc +# endif +# ifndef obstack_chunk_free +# define obstack_chunk_free free +# endif +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +struct hash_table + { + /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1, + for a possibility of N_BUCKETS. Among those, N_BUCKETS_USED buckets + are not empty, there are N_ENTRIES active entries in the table. */ + struct hash_entry *bucket; + struct hash_entry const *bucket_limit; + size_t n_buckets; + size_t n_buckets_used; + size_t n_entries; + + /* Tuning arguments, kept in a physicaly separate structure. */ + const Hash_tuning *tuning; + + /* Three functions are given to `hash_initialize', see the documentation + block for this function. In a word, HASHER randomizes a user entry + into a number up from 0 up to some maximum minus 1; COMPARATOR returns + true if two user entries compare equally; and DATA_FREER is the cleanup + function for a user entry. */ + Hash_hasher hasher; + Hash_comparator comparator; + Hash_data_freer data_freer; + + /* A linked list of freed struct hash_entry structs. */ + struct hash_entry *free_entry_list; + +#if USE_OBSTACK + /* Whenever obstacks are used, it is possible to allocate all overflowed + entries into a single stack, so they all can be freed in a single + operation. It is not clear if the speedup is worth the trouble. */ + struct obstack entry_stack; +#endif + }; + +/* A hash table contains many internal entries, each holding a pointer to + some user provided data (also called a user entry). An entry indistinctly + refers to both the internal entry and its associated user entry. A user + entry contents may be hashed by a randomization function (the hashing + function, or just `hasher' for short) into a number (or `slot') between 0 + and the current table size. At each slot position in the hash table, + starts a linked chain of entries for which the user data all hash to this + slot. A bucket is the collection of all entries hashing to the same slot. + + A good `hasher' function will distribute entries rather evenly in buckets. + In the ideal case, the length of each bucket is roughly the number of + entries divided by the table size. Finding the slot for a data is usually + done in constant time by the `hasher', and the later finding of a precise + entry is linear in time with the size of the bucket. Consequently, a + larger hash table size (that is, a larger number of buckets) is prone to + yielding shorter chains, *given* the `hasher' function behaves properly. + + Long buckets slow down the lookup algorithm. One might use big hash table + sizes in hope to reduce the average length of buckets, but this might + become inordinate, as unused slots in the hash table take some space. The + best bet is to make sure you are using a good `hasher' function (beware + that those are not that easy to write! :-), and to use a table size + larger than the actual number of entries. */ + +/* If an insertion makes the ratio of nonempty buckets to table size larger + than the growth threshold (a number between 0.0 and 1.0), then increase + the table size by multiplying by the growth factor (a number greater than + 1.0). The growth threshold defaults to 0.8, and the growth factor + defaults to 1.414, meaning that the table will have doubled its size + every second time 80% of the buckets get used. */ +#define DEFAULT_GROWTH_THRESHOLD 0.8 +#define DEFAULT_GROWTH_FACTOR 1.414 + +/* If a deletion empties a bucket and causes the ratio of used buckets to + table size to become smaller than the shrink threshold (a number between + 0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a + number greater than the shrink threshold but smaller than 1.0). The shrink + threshold and factor default to 0.0 and 1.0, meaning that the table never + shrinks. */ +#define DEFAULT_SHRINK_THRESHOLD 0.0 +#define DEFAULT_SHRINK_FACTOR 1.0 + +/* Use this to initialize or reset a TUNING structure to + some sensible values. */ +static const Hash_tuning default_tuning = + { + DEFAULT_SHRINK_THRESHOLD, + DEFAULT_SHRINK_FACTOR, + DEFAULT_GROWTH_THRESHOLD, + DEFAULT_GROWTH_FACTOR, + false + }; + +/* Information and lookup. */ + +/* The following few functions provide information about the overall hash + table organization: the number of entries, number of buckets and maximum + length of buckets. */ + +/* Return the number of buckets in the hash table. The table size, the total + number of buckets (used plus unused), or the maximum number of slots, are + the same quantity. */ + +size_t +hash_get_n_buckets (const Hash_table *table) +{ + return table->n_buckets; +} + +/* Return the number of slots in use (non-empty buckets). */ + +size_t +hash_get_n_buckets_used (const Hash_table *table) +{ + return table->n_buckets_used; +} + +/* Return the number of active entries. */ + +size_t +hash_get_n_entries (const Hash_table *table) +{ + return table->n_entries; +} + +/* Return the length of the longest chain (bucket). */ + +size_t +hash_get_max_bucket_length (const Hash_table *table) +{ + struct hash_entry const *bucket; + size_t max_bucket_length = 0; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry const *cursor = bucket; + size_t bucket_length = 1; + + while (cursor = cursor->next, cursor) + bucket_length++; + + if (bucket_length > max_bucket_length) + max_bucket_length = bucket_length; + } + } + + return max_bucket_length; +} + +/* Do a mild validation of a hash table, by traversing it and checking two + statistics. */ + +bool +hash_table_ok (const Hash_table *table) +{ + struct hash_entry const *bucket; + size_t n_buckets_used = 0; + size_t n_entries = 0; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry const *cursor = bucket; + + /* Count bucket head. */ + n_buckets_used++; + n_entries++; + + /* Count bucket overflow. */ + while (cursor = cursor->next, cursor) + n_entries++; + } + } + + if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries) + return true; + + return false; +} + +void +hash_print_statistics (const Hash_table *table, FILE *stream) +{ + size_t n_entries = hash_get_n_entries (table); + size_t n_buckets = hash_get_n_buckets (table); + size_t n_buckets_used = hash_get_n_buckets_used (table); + size_t max_bucket_length = hash_get_max_bucket_length (table); + + fprintf (stream, "# entries: %lu\n", (unsigned long int) n_entries); + fprintf (stream, "# buckets: %lu\n", (unsigned long int) n_buckets); + fprintf (stream, "# buckets used: %lu (%.2f%%)\n", + (unsigned long int) n_buckets_used, + (100.0 * n_buckets_used) / n_buckets); + fprintf (stream, "max bucket length: %lu\n", + (unsigned long int) max_bucket_length); +} + +/* If ENTRY matches an entry already in the hash table, return the + entry from the table. Otherwise, return NULL. */ + +void * +hash_lookup (const Hash_table *table, const void *entry) +{ + struct hash_entry const *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry const *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + if (bucket->data == NULL) + return NULL; + + for (cursor = bucket; cursor; cursor = cursor->next) + if (table->comparator (entry, cursor->data)) + return cursor->data; + + return NULL; +} + +/* Walking. */ + +/* The functions in this page traverse the hash table and process the + contained entries. For the traversal to work properly, the hash table + should not be resized nor modified while any particular entry is being + processed. In particular, entries should not be added or removed. */ + +/* Return the first data in the table, or NULL if the table is empty. */ + +void * +hash_get_first (const Hash_table *table) +{ + struct hash_entry const *bucket; + + if (table->n_entries == 0) + return NULL; + + for (bucket = table->bucket; ; bucket++) + if (! (bucket < table->bucket_limit)) + abort (); + else if (bucket->data) + return bucket->data; +} + +/* Return the user data for the entry following ENTRY, where ENTRY has been + returned by a previous call to either `hash_get_first' or `hash_get_next'. + Return NULL if there are no more entries. */ + +void * +hash_get_next (const Hash_table *table, const void *entry) +{ + struct hash_entry const *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry const *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + /* Find next entry in the same bucket. */ + for (cursor = bucket; cursor; cursor = cursor->next) + if (cursor->data == entry && cursor->next) + return cursor->next->data; + + /* Find first entry in any subsequent bucket. */ + while (++bucket < table->bucket_limit) + if (bucket->data) + return bucket->data; + + /* None found. */ + return NULL; +} + +/* Fill BUFFER with pointers to active user entries in the hash table, then + return the number of pointers copied. Do not copy more than BUFFER_SIZE + pointers. */ + +size_t +hash_get_entries (const Hash_table *table, void **buffer, + size_t buffer_size) +{ + size_t counter = 0; + struct hash_entry const *bucket; + struct hash_entry const *cursor; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + if (counter >= buffer_size) + return counter; + buffer[counter++] = cursor->data; + } + } + } + + return counter; +} + +/* Call a PROCESSOR function for each entry of a hash table, and return the + number of entries for which the processor function returned success. A + pointer to some PROCESSOR_DATA which will be made available to each call to + the processor function. The PROCESSOR accepts two arguments: the first is + the user entry being walked into, the second is the value of PROCESSOR_DATA + as received. The walking continue for as long as the PROCESSOR function + returns nonzero. When it returns zero, the walking is interrupted. */ + +size_t +hash_do_for_each (const Hash_table *table, Hash_processor processor, + void *processor_data) +{ + size_t counter = 0; + struct hash_entry const *bucket; + struct hash_entry const *cursor; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + if (!(*processor) (cursor->data, processor_data)) + return counter; + counter++; + } + } + } + + return counter; +} + +/* Allocation and clean-up. */ + +/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1. + This is a convenience routine for constructing other hashing functions. */ + +#if USE_DIFF_HASH + +/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see + B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm, + Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash + algorithms tend to be domain-specific, so what's good for [diffutils'] io.c + may not be good for your application." */ + +size_t +hash_string (const char *string, size_t n_buckets) +{ +# define ROTATE_LEFT(Value, Shift) \ + ((Value) << (Shift) | (Value) >> ((sizeof (size_t) * CHAR_BIT) - (Shift))) +# define HASH_ONE_CHAR(Value, Byte) \ + ((Byte) + ROTATE_LEFT (Value, 7)) + + size_t value = 0; + unsigned char ch; + + for (; (ch = *string); string++) + value = HASH_ONE_CHAR (value, ch); + return value % n_buckets; + +# undef ROTATE_LEFT +# undef HASH_ONE_CHAR +} + +#else /* not USE_DIFF_HASH */ + +/* This one comes from `recode', and performs a bit better than the above as + per a few experiments. It is inspired from a hashing routine found in the + very old Cyber `snoop', itself written in typical Greg Mansfield style. + (By the way, what happened to this excellent man? Is he still alive?) */ + +size_t +hash_string (const char *string, size_t n_buckets) +{ + size_t value = 0; + unsigned char ch; + + for (; (ch = *string); string++) + value = (value * 31 + ch) % n_buckets; + return value; +} + +#endif /* not USE_DIFF_HASH */ + +/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd + number at least equal to 11. */ + +static bool +is_prime (size_t candidate) +{ + size_t divisor = 3; + size_t square = divisor * divisor; + + while (square < candidate && (candidate % divisor)) + { + divisor++; + square += 4 * divisor; + divisor++; + } + + return (candidate % divisor ? true : false); +} + +/* Round a given CANDIDATE number up to the nearest prime, and return that + prime. Primes lower than 10 are merely skipped. */ + +static size_t +next_prime (size_t candidate) +{ + /* Skip small primes. */ + if (candidate < 10) + candidate = 10; + + /* Make it definitely odd. */ + candidate |= 1; + + while (!is_prime (candidate)) + candidate += 2; + + return candidate; +} + +void +hash_reset_tuning (Hash_tuning *tuning) +{ + *tuning = default_tuning; +} + +/* For the given hash TABLE, check the user supplied tuning structure for + reasonable values, and return true if there is no gross error with it. + Otherwise, definitively reset the TUNING field to some acceptable default + in the hash table (that is, the user loses the right of further modifying + tuning arguments), and return false. */ + +static bool +check_tuning (Hash_table *table) +{ + const Hash_tuning *tuning = table->tuning; + + /* Be a bit stricter than mathematics would require, so that + rounding errors in size calculations do not cause allocations to + fail to grow or shrink as they should. The smallest allocation + is 11 (due to next_prime's algorithm), so an epsilon of 0.1 + should be good enough. */ + float epsilon = 0.1f; + + if (epsilon < tuning->growth_threshold + && tuning->growth_threshold < 1 - epsilon + && 1 + epsilon < tuning->growth_factor + && 0 <= tuning->shrink_threshold + && tuning->shrink_threshold + epsilon < tuning->shrink_factor + && tuning->shrink_factor <= 1 + && tuning->shrink_threshold + epsilon < tuning->growth_threshold) + return true; + + table->tuning = &default_tuning; + return false; +} + +/* Allocate and return a new hash table, or NULL upon failure. The initial + number of buckets is automatically selected so as to _guarantee_ that you + may insert at least CANDIDATE different user entries before any growth of + the hash table size occurs. So, if have a reasonably tight a-priori upper + bound on the number of entries you intend to insert in the hash table, you + may save some table memory and insertion time, by specifying it here. If + the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE + argument has its meaning changed to the wanted number of buckets. + + TUNING points to a structure of user-supplied values, in case some fine + tuning is wanted over the default behavior of the hasher. If TUNING is + NULL, the default tuning parameters are used instead. + + The user-supplied HASHER function should be provided. It accepts two + arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a + slot number for that entry which should be in the range 0..TABLE_SIZE-1. + This slot number is then returned. + + The user-supplied COMPARATOR function should be provided. It accepts two + arguments pointing to user data, it then returns true for a pair of entries + that compare equal, or false otherwise. This function is internally called + on entries which are already known to hash to the same bucket index. + + The user-supplied DATA_FREER function, when not NULL, may be later called + with the user data as an argument, just before the entry containing the + data gets freed. This happens from within `hash_free' or `hash_clear'. + You should specify this function only if you want these functions to free + all of your `data' data. This is typically the case when your data is + simply an auxiliary struct that you have malloc'd to aggregate several + values. */ + +Hash_table * +hash_initialize (size_t candidate, const Hash_tuning *tuning, + Hash_hasher hasher, Hash_comparator comparator, + Hash_data_freer data_freer) +{ + Hash_table *table; + + if (hasher == NULL || comparator == NULL) + return NULL; + + table = malloc (sizeof *table); + if (table == NULL) + return NULL; + + if (!tuning) + tuning = &default_tuning; + table->tuning = tuning; + if (!check_tuning (table)) + { + /* Fail if the tuning options are invalid. This is the only occasion + when the user gets some feedback about it. Once the table is created, + if the user provides invalid tuning options, we silently revert to + using the defaults, and ignore further request to change the tuning + options. */ + goto fail; + } + + if (!tuning->is_n_buckets) + { + float new_candidate = candidate / tuning->growth_threshold; + if (SIZE_MAX <= new_candidate) + goto fail; + candidate = new_candidate; + } + + if (xalloc_oversized (candidate, sizeof *table->bucket)) + goto fail; + table->n_buckets = next_prime (candidate); + if (xalloc_oversized (table->n_buckets, sizeof *table->bucket)) + goto fail; + + table->bucket = calloc (table->n_buckets, sizeof *table->bucket); + table->bucket_limit = table->bucket + table->n_buckets; + table->n_buckets_used = 0; + table->n_entries = 0; + + table->hasher = hasher; + table->comparator = comparator; + table->data_freer = data_freer; + + table->free_entry_list = NULL; +#if USE_OBSTACK + obstack_init (&table->entry_stack); +#endif + return table; + + fail: + free (table); + return NULL; +} + +/* Make all buckets empty, placing any chained entries on the free list. + Apply the user-specified function data_freer (if any) to the datas of any + affected entries. */ + +void +hash_clear (Hash_table *table) +{ + struct hash_entry *bucket; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + struct hash_entry *cursor; + struct hash_entry *next; + + /* Free the bucket overflow. */ + for (cursor = bucket->next; cursor; cursor = next) + { + if (table->data_freer) + (*table->data_freer) (cursor->data); + cursor->data = NULL; + + next = cursor->next; + /* Relinking is done one entry at a time, as it is to be expected + that overflows are either rare or short. */ + cursor->next = table->free_entry_list; + table->free_entry_list = cursor; + } + + /* Free the bucket head. */ + if (table->data_freer) + (*table->data_freer) (bucket->data); + bucket->data = NULL; + bucket->next = NULL; + } + } + + table->n_buckets_used = 0; + table->n_entries = 0; +} + +/* Reclaim all storage associated with a hash table. If a data_freer + function has been supplied by the user when the hash table was created, + this function applies it to the data of each entry before freeing that + entry. */ + +void +hash_free (Hash_table *table) +{ + struct hash_entry *bucket; + struct hash_entry *cursor; + struct hash_entry *next; + + /* Call the user data_freer function. */ + if (table->data_freer && table->n_entries) + { + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + if (bucket->data) + { + for (cursor = bucket; cursor; cursor = cursor->next) + { + (*table->data_freer) (cursor->data); + } + } + } + } + +#if USE_OBSTACK + + obstack_free (&table->entry_stack, NULL); + +#else + + /* Free all bucket overflowed entries. */ + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + for (cursor = bucket->next; cursor; cursor = next) + { + next = cursor->next; + free (cursor); + } + } + + /* Also reclaim the internal list of previously freed entries. */ + for (cursor = table->free_entry_list; cursor; cursor = next) + { + next = cursor->next; + free (cursor); + } + +#endif + + /* Free the remainder of the hash table structure. */ + free (table->bucket); + free (table); +} + +/* Insertion and deletion. */ + +/* Get a new hash entry for a bucket overflow, possibly by reclying a + previously freed one. If this is not possible, allocate a new one. */ + +static struct hash_entry * +allocate_entry (Hash_table *table) +{ + struct hash_entry *new; + + if (table->free_entry_list) + { + new = table->free_entry_list; + table->free_entry_list = new->next; + } + else + { +#if USE_OBSTACK + new = obstack_alloc (&table->entry_stack, sizeof *new); +#else + new = malloc (sizeof *new); +#endif + } + + return new; +} + +/* Free a hash entry which was part of some bucket overflow, + saving it for later recycling. */ + +static void +free_entry (Hash_table *table, struct hash_entry *entry) +{ + entry->data = NULL; + entry->next = table->free_entry_list; + table->free_entry_list = entry; +} + +/* This private function is used to help with insertion and deletion. When + ENTRY matches an entry in the table, return a pointer to the corresponding + user data and set *BUCKET_HEAD to the head of the selected bucket. + Otherwise, return NULL. When DELETE is true and ENTRY matches an entry in + the table, unlink the matching entry. */ + +static void * +hash_find_entry (Hash_table *table, const void *entry, + struct hash_entry **bucket_head, bool delete) +{ + struct hash_entry *bucket + = table->bucket + table->hasher (entry, table->n_buckets); + struct hash_entry *cursor; + + if (! (bucket < table->bucket_limit)) + abort (); + + *bucket_head = bucket; + + /* Test for empty bucket. */ + if (bucket->data == NULL) + return NULL; + + /* See if the entry is the first in the bucket. */ + if ((*table->comparator) (entry, bucket->data)) + { + void *data = bucket->data; + + if (delete) + { + if (bucket->next) + { + struct hash_entry *next = bucket->next; + + /* Bump the first overflow entry into the bucket head, then save + the previous first overflow entry for later recycling. */ + *bucket = *next; + free_entry (table, next); + } + else + { + bucket->data = NULL; + } + } + + return data; + } + + /* Scan the bucket overflow. */ + for (cursor = bucket; cursor->next; cursor = cursor->next) + { + if ((*table->comparator) (entry, cursor->next->data)) + { + void *data = cursor->next->data; + + if (delete) + { + struct hash_entry *next = cursor->next; + + /* Unlink the entry to delete, then save the freed entry for later + recycling. */ + cursor->next = next->next; + free_entry (table, next); + } + + return data; + } + } + + /* No entry found. */ + return NULL; +} + +/* For an already existing hash table, change the number of buckets through + specifying CANDIDATE. The contents of the hash table are preserved. The + new number of buckets is automatically selected so as to _guarantee_ that + the table may receive at least CANDIDATE different user entries, including + those already in the table, before any other growth of the hash table size + occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the + exact number of buckets desired. */ + +bool +hash_rehash (Hash_table *table, size_t candidate) +{ + Hash_table *new_table; + struct hash_entry *bucket; + struct hash_entry *cursor; + struct hash_entry *next; + + new_table = hash_initialize (candidate, table->tuning, table->hasher, + table->comparator, table->data_freer); + if (new_table == NULL) + return false; + + /* Merely reuse the extra old space into the new table. */ +#if USE_OBSTACK + obstack_free (&new_table->entry_stack, NULL); + new_table->entry_stack = table->entry_stack; +#endif + new_table->free_entry_list = table->free_entry_list; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + if (bucket->data) + for (cursor = bucket; cursor; cursor = next) + { + void *data = cursor->data; + struct hash_entry *new_bucket + = (new_table->bucket + + new_table->hasher (data, new_table->n_buckets)); + + if (! (new_bucket < new_table->bucket_limit)) + abort (); + + next = cursor->next; + + if (new_bucket->data) + { + if (cursor == bucket) + { + /* Allocate or recycle an entry, when moving from a bucket + header into a bucket overflow. */ + struct hash_entry *new_entry = allocate_entry (new_table); + + if (new_entry == NULL) + return false; + + new_entry->data = data; + new_entry->next = new_bucket->next; + new_bucket->next = new_entry; + } + else + { + /* Merely relink an existing entry, when moving from a + bucket overflow into a bucket overflow. */ + cursor->next = new_bucket->next; + new_bucket->next = cursor; + } + } + else + { + /* Free an existing entry, when moving from a bucket + overflow into a bucket header. Also take care of the + simple case of moving from a bucket header into a bucket + header. */ + new_bucket->data = data; + new_table->n_buckets_used++; + if (cursor != bucket) + free_entry (new_table, cursor); + } + } + + free (table->bucket); + table->bucket = new_table->bucket; + table->bucket_limit = new_table->bucket_limit; + table->n_buckets = new_table->n_buckets; + table->n_buckets_used = new_table->n_buckets_used; + table->free_entry_list = new_table->free_entry_list; + /* table->n_entries already holds its value. */ +#if USE_OBSTACK + table->entry_stack = new_table->entry_stack; +#endif + free (new_table); + + return true; +} + +/* If ENTRY matches an entry already in the hash table, return the pointer + to the entry from the table. Otherwise, insert ENTRY and return ENTRY. + Return NULL if the storage required for insertion cannot be allocated. */ + +void * +hash_insert (Hash_table *table, const void *entry) +{ + void *data; + struct hash_entry *bucket; + + /* The caller cannot insert a NULL entry. */ + if (! entry) + abort (); + + /* If there's a matching entry already in the table, return that. */ + if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL) + return data; + + /* ENTRY is not matched, it should be inserted. */ + + if (bucket->data) + { + struct hash_entry *new_entry = allocate_entry (table); + + if (new_entry == NULL) + return NULL; + + /* Add ENTRY in the overflow of the bucket. */ + + new_entry->data = (void *) entry; + new_entry->next = bucket->next; + bucket->next = new_entry; + table->n_entries++; + return (void *) entry; + } + + /* Add ENTRY right in the bucket head. */ + + bucket->data = (void *) entry; + table->n_entries++; + table->n_buckets_used++; + + /* If the growth threshold of the buckets in use has been reached, increase + the table size and rehash. There's no point in checking the number of + entries: if the hashing function is ill-conditioned, rehashing is not + likely to improve it. */ + + if (table->n_buckets_used + > table->tuning->growth_threshold * table->n_buckets) + { + /* Check more fully, before starting real work. If tuning arguments + became invalid, the second check will rely on proper defaults. */ + check_tuning (table); + if (table->n_buckets_used + > table->tuning->growth_threshold * table->n_buckets) + { + const Hash_tuning *tuning = table->tuning; + float candidate = + (tuning->is_n_buckets + ? (table->n_buckets * tuning->growth_factor) + : (table->n_buckets * tuning->growth_factor + * tuning->growth_threshold)); + + if (SIZE_MAX <= candidate) + return NULL; + + /* If the rehash fails, arrange to return NULL. */ + if (!hash_rehash (table, candidate)) + entry = NULL; + } + } + + return (void *) entry; +} + +/* If ENTRY is already in the table, remove it and return the just-deleted + data (the user may want to deallocate its storage). If ENTRY is not in the + table, don't modify the table and return NULL. */ + +void * +hash_delete (Hash_table *table, const void *entry) +{ + void *data; + struct hash_entry *bucket; + + data = hash_find_entry (table, entry, &bucket, true); + if (!data) + return NULL; + + table->n_entries--; + if (!bucket->data) + { + table->n_buckets_used--; + + /* If the shrink threshold of the buckets in use has been reached, + rehash into a smaller table. */ + + if (table->n_buckets_used + < table->tuning->shrink_threshold * table->n_buckets) + { + /* Check more fully, before starting real work. If tuning arguments + became invalid, the second check will rely on proper defaults. */ + check_tuning (table); + if (table->n_buckets_used + < table->tuning->shrink_threshold * table->n_buckets) + { + const Hash_tuning *tuning = table->tuning; + size_t candidate = + (tuning->is_n_buckets + ? table->n_buckets * tuning->shrink_factor + : (table->n_buckets * tuning->shrink_factor + * tuning->growth_threshold)); + + hash_rehash (table, candidate); + } + } + } + + return data; +} + +/* Testing. */ + +#if TESTING + +void +hash_print (const Hash_table *table) +{ + struct hash_entry const *bucket; + + for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) + { + struct hash_entry *cursor; + + if (bucket) + printf ("%lu:\n", (unsigned long int) (bucket - table->bucket)); + + for (cursor = bucket; cursor; cursor = cursor->next) + { + char const *s = cursor->data; + /* FIXME */ + if (s) + printf (" %s\n", s); + } + } +} + +#endif /* TESTING */ diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 00000000..ab63a863 --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,88 @@ +/* hash - hashing table processing. + Copyright (C) 1998, 1999, 2001, 2003 Free Software Foundation, Inc. + Written by Jim Meyering <meyering@ascend.com>, 1998. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* A generic hash table package. */ + +/* Make sure USE_OBSTACK is defined to 1 if you want the allocator to use + obstacks instead of malloc, and recompile `hash.c' with same setting. */ + +#ifndef HASH_H_ +# define HASH_H_ + +# include <stdio.h> +# include <stdbool.h> + +typedef size_t (*Hash_hasher) (const void *, size_t); +typedef bool (*Hash_comparator) (const void *, const void *); +typedef void (*Hash_data_freer) (void *); +typedef bool (*Hash_processor) (void *, void *); + +struct hash_entry + { + void *data; + struct hash_entry *next; + }; + +struct hash_tuning + { + /* This structure is mainly used for `hash_initialize', see the block + documentation of `hash_reset_tuning' for more complete comments. */ + + float shrink_threshold; /* ratio of used buckets to trigger a shrink */ + float shrink_factor; /* ratio of new smaller size to original size */ + float growth_threshold; /* ratio of used buckets to trigger a growth */ + float growth_factor; /* ratio of new bigger size to original size */ + bool is_n_buckets; /* if CANDIDATE really means table size */ + }; + +typedef struct hash_tuning Hash_tuning; + +struct hash_table; + +typedef struct hash_table Hash_table; + +/* Information and lookup. */ +size_t hash_get_n_buckets (const Hash_table *); +size_t hash_get_n_buckets_used (const Hash_table *); +size_t hash_get_n_entries (const Hash_table *); +size_t hash_get_max_bucket_length (const Hash_table *); +bool hash_table_ok (const Hash_table *); +void hash_print_statistics (const Hash_table *, FILE *); +void *hash_lookup (const Hash_table *, const void *); + +/* Walking. */ +void *hash_get_first (const Hash_table *); +void *hash_get_next (const Hash_table *, const void *); +size_t hash_get_entries (const Hash_table *, void **, size_t); +size_t hash_do_for_each (const Hash_table *, Hash_processor, void *); + +/* Allocation and clean-up. */ +size_t hash_string (const char *, size_t); +void hash_reset_tuning (Hash_tuning *); +Hash_table *hash_initialize (size_t, const Hash_tuning *, + Hash_hasher, Hash_comparator, + Hash_data_freer); +void hash_clear (Hash_table *); +void hash_free (Hash_table *); + +/* Insertion and deletion. */ +bool hash_rehash (Hash_table *, size_t); +void *hash_insert (Hash_table *, const void *); +void *hash_delete (Hash_table *, const void *); + +#endif diff --git a/lib/lbitset.c b/lib/lbitset.c new file mode 100644 index 00000000..7d47a052 --- /dev/null +++ b/lib/lbitset.c @@ -0,0 +1,1405 @@ +/* Functions to support link list bitsets. + Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "lbitset.h" +#include "obstack.h" +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* This file implements linked-list bitsets. These bitsets can be of + arbitrary length and are more efficient than arrays of bits for + large sparse sets. + + Usually if all the bits in an element are zero we remove the element + from the list. However, a side effect of the bit caching is that we + do not always notice when an element becomes zero. Hence the + lbitset_weed function which removes zero elements. */ + + +/* Number of words to use for each element. The larger the value the + greater the size of the cache and the shorter the time to find a given bit + but the more memory wasted for sparse bitsets and the longer the time + to search for set bits. + + The routines that dominate timing profiles are lbitset_elt_find + and lbitset_elt_link, especially when accessing the bits randomly. */ + +#define LBITSET_ELT_WORDS 2 + +typedef bitset_word lbitset_word; + +#define LBITSET_WORD_BITS BITSET_WORD_BITS + +/* Number of bits stored in each element. */ +#define LBITSET_ELT_BITS \ + ((unsigned int) (LBITSET_ELT_WORDS * LBITSET_WORD_BITS)) + +/* Lbitset element. We use an array of bits for each element. + These are linked together in a doubly-linked list. */ +typedef struct lbitset_elt_struct +{ + struct lbitset_elt_struct *next; /* Next element. */ + struct lbitset_elt_struct *prev; /* Previous element. */ + bitset_windex index; /* bitno / BITSET_WORD_BITS. */ + bitset_word words[LBITSET_ELT_WORDS]; /* Bits that are set. */ +} +lbitset_elt; + + +enum lbitset_find_mode + { LBITSET_FIND, LBITSET_CREATE, LBITSET_SUBST }; + +static lbitset_elt lbitset_zero_elts[3]; /* Elements of all zero bits. */ + +/* Obstack to allocate bitset elements from. */ +static struct obstack lbitset_obstack; +static bool lbitset_obstack_init = false; +static lbitset_elt *lbitset_free_list; /* Free list of bitset elements. */ + +extern void debug_lbitset (bitset); + +#define LBITSET_CURRENT1(X) \ + ((lbitset_elt *) (void *) ((char *) (X) - offsetof (lbitset_elt, words))) + +#define LBITSET_CURRENT(X) LBITSET_CURRENT1((X)->b.cdata) + +#define LBITSET_HEAD(X) ((X)->l.head) +#define LBITSET_TAIL(X) ((X)->l.tail) + +/* Allocate a lbitset element. The bits are not cleared. */ +static inline lbitset_elt * +lbitset_elt_alloc (void) +{ + lbitset_elt *elt; + + if (lbitset_free_list != 0) + { + elt = lbitset_free_list; + lbitset_free_list = elt->next; + } + else + { + if (!lbitset_obstack_init) + { + lbitset_obstack_init = true; + + /* Let particular systems override the size of a chunk. */ + +#ifndef OBSTACK_CHUNK_SIZE +#define OBSTACK_CHUNK_SIZE 0 +#endif + + /* Let them override the alloc and free routines too. */ + +#ifndef OBSTACK_CHUNK_ALLOC +#define OBSTACK_CHUNK_ALLOC xmalloc +#endif + +#ifndef OBSTACK_CHUNK_FREE +#define OBSTACK_CHUNK_FREE free +#endif + +#if ! defined __GNUC__ || __GNUC__ < 2 +#define __alignof__(type) 0 +#endif + + obstack_specify_allocation (&lbitset_obstack, OBSTACK_CHUNK_SIZE, + __alignof__ (lbitset_elt), + OBSTACK_CHUNK_ALLOC, + OBSTACK_CHUNK_FREE); + } + + /* Perhaps we should add a number of new elements to the free + list. */ + elt = (lbitset_elt *) obstack_alloc (&lbitset_obstack, + sizeof (lbitset_elt)); + } + + return elt; +} + + +/* Allocate a lbitset element. The bits are cleared. */ +static inline lbitset_elt * +lbitset_elt_calloc (void) +{ + lbitset_elt *elt; + + elt = lbitset_elt_alloc (); + memset (elt->words, 0, sizeof (elt->words)); + return elt; +} + + +static inline void +lbitset_elt_free (lbitset_elt *elt) +{ + elt->next = lbitset_free_list; + lbitset_free_list = elt; +} + + +/* Unlink element ELT from bitset BSET. */ +static inline void +lbitset_elt_unlink (bitset bset, lbitset_elt *elt) +{ + lbitset_elt *next = elt->next; + lbitset_elt *prev = elt->prev; + + if (prev) + prev->next = next; + + if (next) + next->prev = prev; + + if (LBITSET_HEAD (bset) == elt) + LBITSET_HEAD (bset) = next; + if (LBITSET_TAIL (bset) == elt) + LBITSET_TAIL (bset) = prev; + + /* Update cache pointer. Since the first thing we try is to insert + before current, make current the next entry in preference to the + previous. */ + if (LBITSET_CURRENT (bset) == elt) + { + if (next) + { + bset->b.cdata = next->words; + bset->b.cindex = next->index; + } + else if (prev) + { + bset->b.cdata = prev->words; + bset->b.cindex = prev->index; + } + else + { + bset->b.csize = 0; + bset->b.cdata = 0; + } + } + + lbitset_elt_free (elt); +} + + +/* Cut the chain of bitset BSET before element ELT and free the + elements. */ +static inline void +lbitset_prune (bitset bset, lbitset_elt *elt) +{ + lbitset_elt *next; + + if (!elt) + return; + + if (elt->prev) + { + LBITSET_TAIL (bset) = elt->prev; + bset->b.cdata = elt->prev->words; + bset->b.cindex = elt->prev->index; + elt->prev->next = 0; + } + else + { + LBITSET_HEAD (bset) = 0; + LBITSET_TAIL (bset) = 0; + bset->b.cdata = 0; + bset->b.csize = 0; + } + + for (; elt; elt = next) + { + next = elt->next; + lbitset_elt_free (elt); + } +} + + +/* Are all bits in an element zero? */ +static inline bool +lbitset_elt_zero_p (lbitset_elt *elt) +{ + int i; + + for (i = 0; i < LBITSET_ELT_WORDS; i++) + if (elt->words[i]) + return false; + + return true; +} + + +/* Link the bitset element into the current bitset linked list. */ +static inline void +lbitset_elt_link (bitset bset, lbitset_elt *elt) +{ + bitset_windex windex = elt->index; + lbitset_elt *ptr; + lbitset_elt *current; + + if (bset->b.csize) + current = LBITSET_CURRENT (bset); + else + current = LBITSET_HEAD (bset); + + /* If this is the first and only element, add it in. */ + if (LBITSET_HEAD (bset) == 0) + { + elt->next = elt->prev = 0; + LBITSET_HEAD (bset) = elt; + LBITSET_TAIL (bset) = elt; + } + + /* If this index is less than that of the current element, it goes + somewhere before the current element. */ + else if (windex < bset->b.cindex) + { + for (ptr = current; + ptr->prev && ptr->prev->index > windex; ptr = ptr->prev) + continue; + + if (ptr->prev) + ptr->prev->next = elt; + else + LBITSET_HEAD (bset) = elt; + + elt->prev = ptr->prev; + elt->next = ptr; + ptr->prev = elt; + } + + /* Otherwise, it must go somewhere after the current element. */ + else + { + for (ptr = current; + ptr->next && ptr->next->index < windex; ptr = ptr->next) + continue; + + if (ptr->next) + ptr->next->prev = elt; + else + LBITSET_TAIL (bset) = elt; + + elt->next = ptr->next; + elt->prev = ptr; + ptr->next = elt; + } + + /* Set up so this is the first element searched. */ + bset->b.cindex = windex; + bset->b.csize = LBITSET_ELT_WORDS; + bset->b.cdata = elt->words; +} + + +static lbitset_elt * +lbitset_elt_find (bitset bset, bitset_windex windex, + enum lbitset_find_mode mode) +{ + lbitset_elt *elt; + lbitset_elt *current; + + if (bset->b.csize) + { + current = LBITSET_CURRENT (bset); + /* Check if element is the cached element. */ + if ((windex - bset->b.cindex) < bset->b.csize) + return current; + } + else + { + current = LBITSET_HEAD (bset); + } + + if (current) + { + if (windex < bset->b.cindex) + { + for (elt = current; + elt->prev && elt->index > windex; elt = elt->prev) + continue; + } + else + { + for (elt = current; + elt->next && (elt->index + LBITSET_ELT_WORDS - 1) < windex; + elt = elt->next) + continue; + } + + /* ELT is the nearest to the one we want. If it's not the one + we want, the one we want does not exist. */ + if (elt && (windex - elt->index) < LBITSET_ELT_WORDS) + { + bset->b.cindex = elt->index; + bset->b.csize = LBITSET_ELT_WORDS; + bset->b.cdata = elt->words; + return elt; + } + } + + switch (mode) + { + default: + abort (); + + case LBITSET_FIND: + return 0; + + case LBITSET_CREATE: + windex -= windex % LBITSET_ELT_WORDS; + + elt = lbitset_elt_calloc (); + elt->index = windex; + lbitset_elt_link (bset, elt); + return elt; + + case LBITSET_SUBST: + return &lbitset_zero_elts[0]; + } +} + + +/* Weed out the zero elements from the list. */ +static inline void +lbitset_weed (bitset bset) +{ + lbitset_elt *elt; + lbitset_elt *next; + + for (elt = LBITSET_HEAD (bset); elt; elt = next) + { + next = elt->next; + if (lbitset_elt_zero_p (elt)) + lbitset_elt_unlink (bset, elt); + } +} + + +/* Set all bits in the bitset to zero. */ +static void +lbitset_zero (bitset bset) +{ + lbitset_elt *head; + + head = LBITSET_HEAD (bset); + if (!head) + return; + + /* Clear a bitset by freeing the linked list at the head element. */ + lbitset_prune (bset, head); +} + + +/* Is DST == SRC? */ +static inline bool +lbitset_equal_p (bitset dst, bitset src) +{ + lbitset_elt *selt; + lbitset_elt *delt; + int j; + + if (src == dst) + return true; + + lbitset_weed (src); + lbitset_weed (dst); + for (selt = LBITSET_HEAD (src), delt = LBITSET_HEAD (dst); + selt && delt; selt = selt->next, delt = delt->next) + { + if (selt->index != delt->index) + return false; + + for (j = 0; j < LBITSET_ELT_WORDS; j++) + if (delt->words[j] != selt->words[j]) + return false; + } + return !selt && !delt; +} + + +/* Copy bits from bitset SRC to bitset DST. */ +static inline void +lbitset_copy (bitset dst, bitset src) +{ + lbitset_elt *elt; + lbitset_elt *head; + lbitset_elt *prev; + lbitset_elt *tmp; + + if (src == dst) + return; + + lbitset_zero (dst); + + head = LBITSET_HEAD (src); + if (!head) + return; + + prev = 0; + for (elt = head; elt; elt = elt->next) + { + tmp = lbitset_elt_alloc (); + tmp->index = elt->index; + tmp->prev = prev; + tmp->next = 0; + if (prev) + prev->next = tmp; + else + LBITSET_HEAD (dst) = tmp; + prev = tmp; + + memcpy (tmp->words, elt->words, sizeof (elt->words)); + } + LBITSET_TAIL (dst) = tmp; + + dst->b.csize = LBITSET_ELT_WORDS; + dst->b.cdata = LBITSET_HEAD (dst)->words; + dst->b.cindex = LBITSET_HEAD (dst)->index; +} + + +/* Copy bits from bitset SRC to bitset DST. Return true if + bitsets different. */ +static inline bool +lbitset_copy_cmp (bitset dst, bitset src) +{ + if (src == dst) + return false; + + if (!LBITSET_HEAD (dst)) + { + lbitset_copy (dst, src); + return LBITSET_HEAD (src) != 0; + } + + if (lbitset_equal_p (dst, src)) + return false; + + lbitset_copy (dst, src); + return true; +} + + +static bitset_bindex +lbitset_resize (bitset src, bitset_bindex size) +{ + BITSET_NBITS_ (src) = size; + + /* Need to prune any excess bits. FIXME. */ + return size; +} + +/* Set bit BITNO in bitset DST. */ +static void +lbitset_set (bitset dst, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + lbitset_elt_find (dst, windex, LBITSET_CREATE); + + dst->b.cdata[windex - dst->b.cindex] |= + (bitset_word) 1 << (bitno % BITSET_WORD_BITS); +} + + +/* Reset bit BITNO in bitset DST. */ +static void +lbitset_reset (bitset dst, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + if (!lbitset_elt_find (dst, windex, LBITSET_FIND)) + return; + + dst->b.cdata[windex - dst->b.cindex] &= + ~((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); + + /* If all the data is zero, perhaps we should unlink it now... */ +} + + +/* Test bit BITNO in bitset SRC. */ +static bool +lbitset_test (bitset src, bitset_bindex bitno) +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + return (lbitset_elt_find (src, windex, LBITSET_FIND) + && ((src->b.cdata[windex - src->b.cindex] + >> (bitno % BITSET_WORD_BITS)) + & 1)); +} + + +static void +lbitset_free (bitset bset) +{ + lbitset_zero (bset); +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +lbitset_list_reverse (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex rbitno; + bitset_bindex bitno; + unsigned int bcount; + bitset_bindex boffset; + bitset_windex windex; + bitset_bindex count; + lbitset_elt *elt; + bitset_word word; + bitset_bindex n_bits; + + elt = LBITSET_TAIL (bset); + if (!elt) + return 0; + + n_bits = (elt->index + LBITSET_ELT_WORDS) * BITSET_WORD_BITS; + rbitno = *next; + + if (rbitno >= n_bits) + return 0; + + bitno = n_bits - (rbitno + 1); + + windex = bitno / BITSET_WORD_BITS; + + /* Skip back to starting element. */ + for (; elt && elt->index > windex; elt = elt->prev) + continue; + + if (!elt) + return 0; + + if (windex >= elt->index + LBITSET_ELT_WORDS) + { + /* We are trying to start in no-mans land so start + at end of current elt. */ + bcount = BITSET_WORD_BITS - 1; + windex = elt->index + LBITSET_ELT_WORDS - 1; + } + else + { + bcount = bitno % BITSET_WORD_BITS; + } + + count = 0; + boffset = windex * BITSET_WORD_BITS; + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + while (elt) + { + bitset_word *srcp = elt->words; + + for (; (windex - elt->index) < LBITSET_ELT_WORDS; + windex--, boffset -= BITSET_WORD_BITS, + bcount = BITSET_WORD_BITS - 1) + { + word = + srcp[windex - elt->index] << (BITSET_WORD_BITS - 1 - bcount); + + for (; word; bcount--) + { + if (word & BITSET_MSB) + { + list[count++] = boffset + bcount; + if (count >= num) + { + *next = n_bits - (boffset + bcount); + return count; + } + } + word <<= 1; + } + } + + elt = elt->prev; + if (elt) + { + windex = elt->index + LBITSET_ELT_WORDS - 1; + boffset = windex * BITSET_WORD_BITS; + } + } + + *next = n_bits - (boffset + 1); + return count; +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +lbitset_list (bitset bset, bitset_bindex *list, + bitset_bindex num, bitset_bindex *next) +{ + bitset_bindex bitno; + bitset_windex windex; + bitset_bindex count; + lbitset_elt *elt; + lbitset_elt *head; + bitset_word word; + + head = LBITSET_HEAD (bset); + if (!head) + return 0; + + bitno = *next; + count = 0; + + if (!bitno) + { + /* This is the most common case. */ + + /* Start with the first element. */ + elt = head; + windex = elt->index; + bitno = windex * BITSET_WORD_BITS; + } + else + { + windex = bitno / BITSET_WORD_BITS; + + /* Skip to starting element. */ + for (elt = head; + elt && (elt->index + LBITSET_ELT_WORDS - 1) < windex; + elt = elt->next) + continue; + + if (!elt) + return 0; + + if (windex < elt->index) + { + windex = elt->index; + bitno = windex * BITSET_WORD_BITS; + } + else + { + bitset_word *srcp = elt->words; + + /* We are starting within an element. */ + + for (; (windex - elt->index) < LBITSET_ELT_WORDS; windex++) + { + word = srcp[windex - elt->index] >> (bitno % BITSET_WORD_BITS); + + for (; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + bitno = (windex + 1) * BITSET_WORD_BITS; + } + + elt = elt->next; + if (elt) + { + windex = elt->index; + bitno = windex * BITSET_WORD_BITS; + } + } + } + + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + while (elt) + { + int i; + bitset_word *srcp = elt->words; + + if ((count + LBITSET_ELT_BITS) < num) + { + /* The coast is clear, plant boot! */ + +#if LBITSET_ELT_WORDS == 2 + word = srcp[0]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + if (!(word & 0xff)) + { + word >>= 8; + bitno += 8; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + windex++; + bitno = windex * BITSET_WORD_BITS; + + word = srcp[1]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + windex++; + bitno = windex * BITSET_WORD_BITS; +#else + for (i = 0; i < LBITSET_ELT_WORDS; i++) + { + word = srcp[i]; + if (word) + { + if (!(word & 0xffff)) + { + word >>= 16; + bitno += 16; + } + if (!(word & 0xff)) + { + word >>= 8; + bitno += 8; + } + for (; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + windex++; + bitno = windex * BITSET_WORD_BITS; + } +#endif + } + else + { + /* Tread more carefully since we need to check + if array overflows. */ + + for (i = 0; i < LBITSET_ELT_WORDS; i++) + { + for (word = srcp[i]; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + windex++; + bitno = windex * BITSET_WORD_BITS; + } + } + + elt = elt->next; + if (elt) + { + windex = elt->index; + bitno = windex * BITSET_WORD_BITS; + } + } + + *next = bitno; + return count; +} + + +static bool +lbitset_empty_p (bitset dst) +{ + lbitset_elt *elt; + lbitset_elt *next; + + for (elt = LBITSET_HEAD (dst); elt; elt = next) + { + next = elt->next; + if (!lbitset_elt_zero_p (elt)) + return 0; + /* Weed as we go. */ + lbitset_elt_unlink (dst, elt); + } + + return 1; +} + + +/* Ensure that any unused bits within the last element are clear. */ +static inline void +lbitset_unused_clear (bitset dst) +{ + unsigned int last_bit; + bitset_bindex n_bits; + + n_bits = BITSET_SIZE_ (dst); + last_bit = n_bits % LBITSET_ELT_BITS; + + if (last_bit) + { + lbitset_elt *elt; + bitset_windex windex; + bitset_word *srcp; + + elt = LBITSET_TAIL (dst); + srcp = elt->words; + windex = n_bits / BITSET_WORD_BITS; + + srcp[windex - elt->index] &= ((bitset_word) 1 << last_bit) - 1; + windex++; + + for (; (windex - elt->index) < LBITSET_ELT_WORDS; windex++) + srcp[windex - elt->index] = 0; + } +} + + +static void +lbitset_ones (bitset dst) +{ + bitset_windex i; + bitset_windex windex; + lbitset_elt *elt; + + /* This is a decidedly unfriendly operation for a linked list + bitset! It makes a sparse bitset become dense. An alternative + is to have a flag that indicates that the bitset stores the + complement of what it indicates. */ + + windex = (BITSET_SIZE_ (dst) + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS; + + for (i = 0; i < windex; i += LBITSET_ELT_WORDS) + { + /* Create new elements if they cannot be found. */ + elt = lbitset_elt_find (dst, i, LBITSET_CREATE); + memset (elt->words, -1, sizeof (elt->words)); + } + + lbitset_unused_clear (dst); +} + + +static void +lbitset_not (bitset dst, bitset src) +{ + lbitset_elt *elt; + lbitset_elt *selt; + lbitset_elt *delt; + bitset_windex i; + unsigned int j; + bitset_windex windex; + + /* This is another unfriendly operation for a linked list + bitset! */ + elt = LBITSET_TAIL (dst); + + windex = (BITSET_SIZE_ (dst) + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS; + + for (i = 0; i < windex; i += LBITSET_ELT_WORDS) + { + /* Create new elements for dst if they cannot be found + or substitute zero elements if src elements not found. */ + selt = lbitset_elt_find (src, i, LBITSET_SUBST); + delt = lbitset_elt_find (dst, i, LBITSET_CREATE); + + for (j = 0; j < LBITSET_ELT_WORDS; j++) + delt->words[j] = ~selt->words[j]; + } + lbitset_unused_clear (dst); + lbitset_weed (dst); + return; +} + + +/* Is DST == DST | SRC? */ +static bool +lbitset_subset_p (bitset dst, bitset src) +{ + lbitset_elt *selt; + lbitset_elt *delt; + unsigned int j; + + for (selt = LBITSET_HEAD (src), delt = LBITSET_HEAD (dst); + selt || delt; selt = selt->next, delt = delt->next) + { + if (!selt) + selt = &lbitset_zero_elts[0]; + else if (!delt) + delt = &lbitset_zero_elts[0]; + else if (selt->index != delt->index) + { + if (selt->index < delt->index) + { + lbitset_zero_elts[2].next = delt; + delt = &lbitset_zero_elts[2]; + } + else + { + lbitset_zero_elts[1].next = selt; + selt = &lbitset_zero_elts[1]; + } + } + + for (j = 0; j < LBITSET_ELT_WORDS; j++) + if (delt->words[j] != (selt->words[j] | delt->words[j])) + return false; + } + return true; +} + + +/* Is DST & SRC == 0? */ +static bool +lbitset_disjoint_p (bitset dst, bitset src) +{ + lbitset_elt *selt; + lbitset_elt *delt; + unsigned int j; + + for (selt = LBITSET_HEAD (src), delt = LBITSET_HEAD (dst); + selt && delt; selt = selt->next, delt = delt->next) + { + if (selt->index != delt->index) + { + if (selt->index < delt->index) + { + lbitset_zero_elts[2].next = delt; + delt = &lbitset_zero_elts[2]; + } + else + { + lbitset_zero_elts[1].next = selt; + selt = &lbitset_zero_elts[1]; + } + /* Since the elements are different, there is no + intersection of these elements. */ + continue; + } + + for (j = 0; j < LBITSET_ELT_WORDS; j++) + if (selt->words[j] & delt->words[j]) + return false; + } + return true; +} + + +static bool +lbitset_op3_cmp (bitset dst, bitset src1, bitset src2, enum bitset_ops op) +{ + lbitset_elt *selt1 = LBITSET_HEAD (src1); + lbitset_elt *selt2 = LBITSET_HEAD (src2); + lbitset_elt *delt = LBITSET_HEAD (dst); + bitset_windex windex1; + bitset_windex windex2; + bitset_windex windex; + lbitset_elt *stmp1; + lbitset_elt *stmp2; + lbitset_elt *dtmp; + bitset_word *srcp1; + bitset_word *srcp2; + bitset_word *dstp; + bool changed = false; + unsigned int i; + + LBITSET_HEAD (dst) = 0; + dst->b.csize = 0; + + windex1 = (selt1) ? selt1->index : BITSET_WINDEX_MAX; + windex2 = (selt2) ? selt2->index : BITSET_WINDEX_MAX; + + while (selt1 || selt2) + { + /* Figure out whether we need to substitute zero elements for + missing links. */ + if (windex1 == windex2) + { + windex = windex1; + stmp1 = selt1; + stmp2 = selt2; + selt1 = selt1->next; + windex1 = (selt1) ? selt1->index : BITSET_WINDEX_MAX; + selt2 = selt2->next; + windex2 = (selt2) ? selt2->index : BITSET_WINDEX_MAX; + } + else if (windex1 < windex2) + { + windex = windex1; + stmp1 = selt1; + stmp2 = &lbitset_zero_elts[0]; + selt1 = selt1->next; + windex1 = (selt1) ? selt1->index : BITSET_WINDEX_MAX; + } + else + { + windex = windex2; + stmp1 = &lbitset_zero_elts[0]; + stmp2 = selt2; + selt2 = selt2->next; + windex2 = (selt2) ? selt2->index : BITSET_WINDEX_MAX; + } + + /* Find the appropriate element from DST. Begin by discarding + elements that we've skipped. */ + while (delt && delt->index < windex) + { + changed = true; + dtmp = delt; + delt = delt->next; + lbitset_elt_free (dtmp); + } + if (delt && delt->index == windex) + { + dtmp = delt; + delt = delt->next; + } + else + dtmp = lbitset_elt_calloc (); + + /* Do the operation, and if any bits are set, link it into the + linked list. */ + srcp1 = stmp1->words; + srcp2 = stmp2->words; + dstp = dtmp->words; + switch (op) + { + default: + abort (); + + case BITSET_OP_OR: + for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ | *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_AND: + for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ & *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_XOR: + for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ ^ *srcp2++; + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + + case BITSET_OP_ANDN: + for (i = 0; i < LBITSET_ELT_WORDS; i++, dstp++) + { + bitset_word tmp = *srcp1++ & ~(*srcp2++); + + if (*dstp != tmp) + { + changed = true; + *dstp = tmp; + } + } + break; + } + + if (!lbitset_elt_zero_p (dtmp)) + { + dtmp->index = windex; + /* Perhaps this could be optimised... */ + lbitset_elt_link (dst, dtmp); + } + else + { + lbitset_elt_free (dtmp); + } + } + + /* If we have elements of DST left over, free them all. */ + if (delt) + { + changed = true; + lbitset_prune (dst, delt); + } + + return changed; +} + + +static bool +lbitset_and_cmp (bitset dst, bitset src1, bitset src2) +{ + lbitset_elt *selt1 = LBITSET_HEAD (src1); + lbitset_elt *selt2 = LBITSET_HEAD (src2); + bool changed; + + if (!selt2) + { + lbitset_weed (dst); + changed = !LBITSET_HEAD (dst); + lbitset_zero (dst); + return changed; + } + else if (!selt1) + { + lbitset_weed (dst); + changed = !LBITSET_HEAD (dst); + lbitset_zero (dst); + return changed; + } + return lbitset_op3_cmp (dst, src1, src2, BITSET_OP_AND); +} + + +static void +lbitset_and (bitset dst, bitset src1, bitset src2) +{ + lbitset_and_cmp (dst, src1, src2); +} + + +static bool +lbitset_andn_cmp (bitset dst, bitset src1, bitset src2) +{ + lbitset_elt *selt1 = LBITSET_HEAD (src1); + lbitset_elt *selt2 = LBITSET_HEAD (src2); + bool changed; + + if (!selt2) + { + return lbitset_copy_cmp (dst, src1); + } + else if (!selt1) + { + lbitset_weed (dst); + changed = !LBITSET_HEAD (dst); + lbitset_zero (dst); + return changed; + } + return lbitset_op3_cmp (dst, src1, src2, BITSET_OP_ANDN); +} + + +static void +lbitset_andn (bitset dst, bitset src1, bitset src2) +{ + lbitset_andn_cmp (dst, src1, src2); +} + + +static bool +lbitset_or_cmp (bitset dst, bitset src1, bitset src2) +{ + lbitset_elt *selt1 = LBITSET_HEAD (src1); + lbitset_elt *selt2 = LBITSET_HEAD (src2); + + if (!selt2) + { + return lbitset_copy_cmp (dst, src1); + } + else if (!selt1) + { + return lbitset_copy_cmp (dst, src2); + } + return lbitset_op3_cmp (dst, src1, src2, BITSET_OP_OR); +} + + +static void +lbitset_or (bitset dst, bitset src1, bitset src2) +{ + lbitset_or_cmp (dst, src1, src2); +} + + +static bool +lbitset_xor_cmp (bitset dst, bitset src1, bitset src2) +{ + lbitset_elt *selt1 = LBITSET_HEAD (src1); + lbitset_elt *selt2 = LBITSET_HEAD (src2); + + if (!selt2) + { + return lbitset_copy_cmp (dst, src1); + } + else if (!selt1) + { + return lbitset_copy_cmp (dst, src2); + } + return lbitset_op3_cmp (dst, src1, src2, BITSET_OP_XOR); +} + + +static void +lbitset_xor (bitset dst, bitset src1, bitset src2) +{ + lbitset_xor_cmp (dst, src1, src2); +} + + + +/* Vector of operations for linked-list bitsets. */ +struct bitset_vtable lbitset_vtable = { + lbitset_set, + lbitset_reset, + bitset_toggle_, + lbitset_test, + lbitset_resize, + bitset_size_, + bitset_count_, + lbitset_empty_p, + lbitset_ones, + lbitset_zero, + lbitset_copy, + lbitset_disjoint_p, + lbitset_equal_p, + lbitset_not, + lbitset_subset_p, + lbitset_and, + lbitset_and_cmp, + lbitset_andn, + lbitset_andn_cmp, + lbitset_or, + lbitset_or_cmp, + lbitset_xor, + lbitset_xor_cmp, + bitset_and_or_, + bitset_and_or_cmp_, + bitset_andn_or_, + bitset_andn_or_cmp_, + bitset_or_and_, + bitset_or_and_cmp_, + lbitset_list, + lbitset_list_reverse, + lbitset_free, + BITSET_LIST +}; + + +/* Return size of initial structure. */ +size_t +lbitset_bytes (bitset_bindex n_bits ATTRIBUTE_UNUSED) +{ + return sizeof (struct lbitset_struct); +} + + +/* Initialize a bitset. */ +bitset +lbitset_init (bitset bset, bitset_bindex n_bits ATTRIBUTE_UNUSED) +{ + BITSET_NBITS_ (bset) = n_bits; + bset->b.vtable = &lbitset_vtable; + return bset; +} + + +void +lbitset_release_memory (void) +{ + lbitset_free_list = 0; + if (lbitset_obstack_init) + { + lbitset_obstack_init = false; + obstack_free (&lbitset_obstack, NULL); + } +} + + +/* Function to be called from debugger to debug lbitset. */ +void +debug_lbitset (bitset bset) +{ + lbitset_elt *elt; + unsigned int i; + + if (!bset) + return; + + for (elt = LBITSET_HEAD (bset); elt; elt = elt->next) + { + fprintf (stderr, "Elt %lu\n", (unsigned long int) elt->index); + for (i = 0; i < LBITSET_ELT_WORDS; i++) + { + unsigned int j; + bitset_word word; + + word = elt->words[i]; + + fprintf (stderr, " Word %u:", i); + for (j = 0; j < LBITSET_WORD_BITS; j++) + if ((word & ((bitset_word) 1 << j))) + fprintf (stderr, " %u", j); + fprintf (stderr, "\n"); + } + } +} diff --git a/lib/lbitset.h b/lib/lbitset.h new file mode 100644 index 00000000..aaad8345 --- /dev/null +++ b/lib/lbitset.h @@ -0,0 +1,30 @@ +/* Functions to support lbitsets. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _LBITSET_H +#define _LBITSET_H + +#include "bitset.h" + +extern size_t lbitset_bytes (bitset_bindex); + +extern bitset lbitset_init (bitset, bitset_bindex); + +extern void lbitset_release_memory (void); + +#endif diff --git a/lib/libiberty.h b/lib/libiberty.h new file mode 100644 index 00000000..e8629e40 --- /dev/null +++ b/lib/libiberty.h @@ -0,0 +1,36 @@ +/* Fake libiberty.h for Bison. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + + +/* Bison depends on libiberty's implementation of bitsets, which + requires a `libiberty.h' file. This file provides the minimum + services. */ + +#ifndef BISON_LIBIBERTY_H_ +# define BISON_LIBIBERTY_H_ 1 + +# ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +# endif + +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) + +# include "xalloc.h" + +#endif /* ! BISON_LIBIBERTY_H_ */ diff --git a/lib/main.c b/lib/main.c new file mode 100644 index 00000000..98dedf97 --- /dev/null +++ b/lib/main.c @@ -0,0 +1,38 @@ +/* Yacc library main function. + + Copyright (C) 2002 Free Software Foundation, Inc. + + This file is part of Bison, the GNU Compiler Compiler. + + Bison is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bison is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bison; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include <config.h> + +#if HAVE_LOCALE_H +# include <locale.h> +#endif +#if ! HAVE_SETLOCALE +# define setlocale(Category, Locale) +#endif + +int yyparse (void); + +int +main (void) +{ + setlocale (LC_ALL, ""); + return yyparse (); +} diff --git a/lib/malloc.c b/lib/malloc.c new file mode 100644 index 00000000..58fa6116 --- /dev/null +++ b/lib/malloc.c @@ -0,0 +1,36 @@ +/* malloc() function that is glibc compatible. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* written by Jim Meyering */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#undef malloc + +#include <stdlib.h> + +/* Allocate an N-byte block of memory from the heap. + If N is zero, allocate a 1-byte block. */ + +void * +rpl_malloc (size_t n) +{ + if (n == 0) + n = 1; + return malloc (n); +} diff --git a/lib/mbswidth.c b/lib/mbswidth.c new file mode 100644 index 00000000..c9e78d65 --- /dev/null +++ b/lib/mbswidth.c @@ -0,0 +1,221 @@ +/* Determine the number of screen columns needed for a string. + Copyright (C) 2000-2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Bruno Haible <haible@clisp.cons.org>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "mbswidth.h" + +/* Get MB_CUR_MAX. */ +#include <stdlib.h> + +#include <string.h> + +/* Get isprint(). */ +#include <ctype.h> + +/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth(). */ +#if HAVE_WCHAR_H +/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before + <wchar.h>. + BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before + <wchar.h>. */ +# include <stdio.h> +# include <time.h> +# include <wchar.h> +#endif + +/* Get iswprint(), iswcntrl(). */ +#if HAVE_WCTYPE_H +# include <wctype.h> +#endif +#if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +#endif +#if !defined iswcntrl && !HAVE_ISWCNTRL +# define iswcntrl(wc) 0 +#endif + +#ifndef mbsinit +# if !HAVE_MBSINIT +# define mbsinit(ps) 1 +# endif +#endif + +#ifndef HAVE_DECL_WCWIDTH +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_WCWIDTH +int wcwidth (); +#endif + +#ifndef wcwidth +# if !HAVE_WCWIDTH +/* wcwidth doesn't exist, so assume all printable characters have + width 1. */ +# define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1) +# endif +#endif + +/* Get ISPRINT. */ +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif +/* Undefine to protect against the definition in wctype.h of Solaris 2.6. */ +#undef ISPRINT +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#undef ISCNTRL +#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) + +/* Returns the number of columns needed to represent the multibyte + character string pointed to by STRING. If a non-printable character + occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned. + With flags = MBSW_REJECT_INVALID | MBSW_REJECT_UNPRINTABLE, this is + the multibyte analogue of the wcswidth function. + If STRING is not of length < INT_MAX / 2, integer overflow can occur. */ +int +mbswidth (const char *string, int flags) +{ + return mbsnwidth (string, strlen (string), flags); +} + +/* Returns the number of columns needed to represent the multibyte + character string pointed to by STRING of length NBYTES. If a + non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is + specified, -1 is returned. + If NBYTES is not < INT_MAX / 2, integer overflow can occur. */ +int +mbsnwidth (const char *string, size_t nbytes, int flags) +{ + const char *p = string; + const char *plimit = p + nbytes; + int width; + + width = 0; +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + while (p < plimit) + switch (*p) + { + case ' ': case '!': case '"': case '#': case '%': + case '&': case '\'': case '(': case ')': case '*': + case '+': case ',': case '-': case '.': case '/': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ':': case ';': case '<': case '=': case '>': + case '?': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '[': case '\\': case ']': case '^': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': case '{': case '|': case '}': case '~': + /* These characters are printable ASCII characters. */ + p++; + width++; + break; + default: + /* If we have a multibyte sequence, scan it up to its end. */ + { + mbstate_t mbstate; + memset (&mbstate, 0, sizeof mbstate); + do + { + wchar_t wc; + size_t bytes; + int w; + + bytes = mbrtowc (&wc, p, plimit - p, &mbstate); + + if (bytes == (size_t) -1) + /* An invalid multibyte sequence was encountered. */ + { + if (!(flags & MBSW_REJECT_INVALID)) + { + p++; + width++; + break; + } + else + return -1; + } + + if (bytes == (size_t) -2) + /* An incomplete multibyte character at the end. */ + { + if (!(flags & MBSW_REJECT_INVALID)) + { + p = plimit; + width++; + break; + } + else + return -1; + } + + if (bytes == 0) + /* A null wide character was encountered. */ + bytes = 1; + + w = wcwidth (wc); + if (w >= 0) + /* A printable multibyte character. */ + width += w; + else + /* An unprintable multibyte character. */ + if (!(flags & MBSW_REJECT_UNPRINTABLE)) + width += (iswcntrl (wc) ? 0 : 1); + else + return -1; + + p += bytes; + } + while (! mbsinit (&mbstate)); + } + break; + } + return width; + } +#endif + + while (p < plimit) + { + unsigned char c = (unsigned char) *p++; + + if (ISPRINT (c)) + width++; + else if (!(flags & MBSW_REJECT_UNPRINTABLE)) + width += (ISCNTRL (c) ? 0 : 1); + else + return -1; + } + return width; +} diff --git a/lib/mbswidth.h b/lib/mbswidth.h new file mode 100644 index 00000000..1935e0a2 --- /dev/null +++ b/lib/mbswidth.h @@ -0,0 +1,61 @@ +/* Determine the number of screen columns needed for a string. + Copyright (C) 2000-2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <stddef.h> + +/* Avoid a clash of our mbswidth() with a function of the same name defined + in UnixWare 7.1.1 <wchar.h>. We need this #include before the #define + below. + However, we don't want to #include <wchar.h> on all platforms because + - Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before + <wchar.h>. + - BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before + <wchar.h>. */ +#if HAVE_DECL_MBSWIDTH_IN_WCHAR_H +# include <wchar.h> +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Optional flags to influence mbswidth/mbsnwidth behavior. */ + +/* If this bit is set, return -1 upon finding an invalid or incomplete + character. Otherwise, assume invalid characters have width 1. */ +#define MBSW_REJECT_INVALID 1 + +/* If this bit is set, return -1 upon finding a non-printable character. + Otherwise, assume unprintable characters have width 0 if they are + control characters and 1 otherwise. */ +#define MBSW_REJECT_UNPRINTABLE 2 + + +/* Returns the number of screen columns needed for STRING. */ +#define mbswidth gnu_mbswidth /* avoid clash with UnixWare 7.1.1 function */ +extern int mbswidth (const char *string, int flags); + +/* Returns the number of screen columns needed for the NBYTES bytes + starting at BUF. */ +extern int mbsnwidth (const char *buf, size_t nbytes, int flags); + + +#ifdef __cplusplus +} +#endif diff --git a/lib/obstack.c b/lib/obstack.c new file mode 100644 index 00000000..6df0611d --- /dev/null +++ b/lib/obstack.c @@ -0,0 +1,440 @@ +/* obstack.c - subroutines used implicitly by object stack macros + + Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, + Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# include <obstack.h> +# include <shlib-compat.h> +#else +# include "obstack.h" +#endif + +/* NOTE BEFORE MODIFYING THIS FILE: This version number must be + incremented whenever callers compiled using an old obstack.h can no + longer properly call the functions in this obstack.c. */ +#define OBSTACK_INTERFACE_VERSION 1 + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself, and the installed library + supports the same library interface we do. This code is part of the GNU + C Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object + files, it is simpler to just do this in the source for each such file. */ + +#include <stdio.h> /* Random thing to get __GNU_LIBRARY__. */ +#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +# include <gnu-versions.h> +# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#include <stddef.h> + +#ifndef ELIDE_CODE + + +# if HAVE_INTTYPES_H +# include <inttypes.h> +# endif +# if HAVE_STDINT_H || defined _LIBC +# include <stdint.h> +# endif + +/* Determine default alignment. */ +union fooround +{ + uintmax_t i; + long double d; + void *p; +}; +struct fooalign +{ + char c; + union fooround u; +}; +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +enum + { + DEFAULT_ALIGNMENT = offsetof (struct fooalign, u), + DEFAULT_ROUNDING = sizeof (union fooround) + }; + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +# ifndef COPYING_UNIT +# define COPYING_UNIT int +# endif + + +/* The functions allocating more room by calling `obstack_chunk_alloc' + jump to the handler pointed to by `obstack_alloc_failed_handler'. + This can be set to a user defined function which should either + abort gracefully or use longjump - but shouldn't return. This + variable by default points to the internal function + `print_and_abort'. */ +static void print_and_abort (void); +void (*obstack_alloc_failed_handler) (void) = print_and_abort; + +/* Exit value used when `print_and_abort' is used. */ +# include <stdlib.h> +# ifdef _LIBC +int obstack_exit_failure = EXIT_FAILURE; +# else +# include "exitfail.h" +# define obstack_exit_failure exit_failure +# endif + +# ifdef _LIBC +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) +/* A looong time ago (before 1994, anyway; we're not sure) this global variable + was used by non-GNU-C macros to avoid multiple evaluation. The GNU C + library still exports it because somebody might use it. */ +struct obstack *_obstack_compat; +compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0); +# endif +# endif + +/* Define a macro that either calls functions with the traditional malloc/free + calling interface, or calls functions with the mmalloc/mfree interface + (that adds an extra first argument), based on the state of use_extra_arg. + For free, do not use ?:, since some compilers, like the MIPS compilers, + do not allow (expr) ? void : void. */ + +# define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size))) + +# define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ + } while (0) + + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. + + Return nonzero if successful, calls obstack_alloc_failed_handler if + allocation fails. */ + +int +_obstack_begin (struct obstack *h, + int size, int alignment, + void *(*chunkfun) (long), + void (*freefun) (void *)) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->use_extra_arg = 0; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, + alignment - 1); + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +int +_obstack_begin_1 (struct obstack *h, int size, int alignment, + void *(*chunkfun) (void *, long), + void (*freefun) (void *, void *), + void *arg) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->extra_arg = arg; + h->use_extra_arg = 1; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, + alignment - 1); + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (struct obstack *h, int length) +{ + register struct _obstack_chunk *old_chunk = h->chunk; + register struct _obstack_chunk *new_chunk; + register long new_size; + register long obj_size = h->next_free - h->object_base; + register long i; + long already; + char *object_base; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = CALL_CHUNKFUN (h, new_size); + if (!new_chunk) + (*obstack_alloc_failed_handler) (); + h->chunk = new_chunk; + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Compute an aligned object_base in the new chunk */ + object_base = + __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask); + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)object_base)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + object_base[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. + But not if that chunk might contain an empty object. */ + if (! h->maybe_empty_object + && (h->object_base + == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents, + h->alignment_mask))) + { + new_chunk->prev = old_chunk->prev; + CALL_FREEFUN (h, old_chunk); + } + + h->object_base = object_base; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} +# ifdef _LIBC +libc_hidden_def (_obstack_newchunk) +# endif + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +/* Suppress -Wmissing-prototypes warning. We don't want to declare this in + obstack.h because it is just for debugging. */ +int _obstack_allocated_p (struct obstack *h, void *obj); + +int +_obstack_allocated_p (struct obstack *h, void *obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent chunk. */ + while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj)) + { + plp = lp->prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +# undef obstack_free + +void +obstack_free (struct obstack *h, void *obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *) (obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +# ifdef _LIBC +/* Older versions of libc used a function _obstack_free intended to be + called by non-GCC compilers. */ +strong_alias (obstack_free, _obstack_free) +# endif + +int +_obstack_memory_used (struct obstack *h) +{ + register struct _obstack_chunk* lp; + register int nbytes = 0; + + for (lp = h->chunk; lp != 0; lp = lp->prev) + { + nbytes += lp->limit - (char *) lp; + } + return nbytes; +} + +/* Define the error handler. */ +# ifdef _LIBC +# include <libintl.h> +# else +# include "gettext.h" +# endif +# ifndef _ +# define _(msgid) gettext (msgid) +# endif + +# ifdef _LIBC +# include <libio/iolibio.h> +# endif + +# ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(Spec) /* empty */ +# endif +# endif + +static void +__attribute__ ((noreturn)) +print_and_abort (void) +{ + /* Don't change any of these strings. Yes, it would be possible to add + the newline to the string and use fputs or so. But this must not + happen because the "memory exhausted" message appears in other places + like this and the translation should be reused instead of creating + a very similar string which requires a separate translation. */ +# ifdef _LIBC + (void) __fxprintf (NULL, "%s\n", _("memory exhausted")); +# else + fprintf (stderr, "%s\n", _("memory exhausted")); +# endif + exit (obstack_exit_failure); +} + +#endif /* !ELIDE_CODE */ diff --git a/lib/obstack.h b/lib/obstack.h new file mode 100644 index 00000000..95dd438f --- /dev/null +++ b/lib/obstack.h @@ -0,0 +1,508 @@ +/* obstack.h - object stack macros + Copyright (C) 1988-1994,1996-1999,2003,2004,2005 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef _OBSTACK_H +#define _OBSTACK_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* We need the type of a pointer subtraction. If __PTRDIFF_TYPE__ is + defined, as with GNU C, use that; that way we don't pollute the + namespace with <stddef.h>'s symbols. Otherwise, include <stddef.h> + and use ptrdiff_t. */ + +#ifdef __PTRDIFF_TYPE__ +# define PTR_INT_TYPE __PTRDIFF_TYPE__ +#else +# include <stddef.h> +# define PTR_INT_TYPE ptrdiff_t +#endif + +/* If B is the base of an object addressed by P, return the result of + aligning P to the next multiple of A + 1. B and P must be of type + char *. A + 1 must be a power of 2. */ + +#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A))) + +/* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case + where pointers can be converted to integers, aligned as integers, + and converted back again. If PTR_INT_TYPE is narrower than a + pointer (e.g., the AS/400), play it safe and compute the alignment + relative to B. Otherwise, use the faster strategy of computing the + alignment relative to 0. */ + +#define __PTR_ALIGN(B, P, A) \ + __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \ + P, A) + +#include <string.h> + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + union + { + PTR_INT_TYPE tempint; + void *tempptr; + } temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + /* These prototypes vary based on `use_extra_arg', and we use + casts to the prototypeless function type in all assignments, + but having prototypes here quiets -Wstrict-prototypes. */ + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ + unsigned alloc_failed:1; /* No longer used, as we now call the failed + handler on error, but retained for binary + compatibility. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +extern void _obstack_newchunk (struct obstack *, int); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (long), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +extern int _obstack_memory_used (struct obstack *); + +void obstack_free (struct obstack *obstack, void *block); + + +/* Error handler called when `obstack_chunk_alloc' failed to allocate + more memory. This can be set to a user defined function which + should either abort gracefully or use longjump - but shouldn't + return. The default action is to print a message and abort. */ +extern void (*obstack_alloc_failed_handler) (void); + +/* Exit value used when `print_and_abort' is used. */ +extern int obstack_exit_failure; + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((void *) (h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +/* To prevent prototype warnings provide complete argument list. */ +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) (long)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) (long)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) + +#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) (long)) (chunkfun), \ + (void (*) (void *)) (freefun)) + +#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) (void *, long)) (chunkfun), \ + (void (*) (void *, void *)) (freefun), (arg)) + +#define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun)) + +#define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun)) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar)) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#define obstack_memory_used(h) _obstack_memory_used (h) + +#if defined __GNUC__ && defined __STDC__ && __STDC__ +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +# define __extension__ +# endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +# define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +# define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +# define obstack_make_room(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) + +# define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (__o->chunk->prev == 0 \ + && __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \ + __o->chunk->contents, \ + __o->alignment_mask)); }) + +# define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +# define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, 1); \ + obstack_1grow_fast (__o, datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers + or ints, and that the data added so far to the current object + shares that much alignment. */ + +# define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ + obstack_ptr_grow_fast (__o, datum); }) \ + +# define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (int) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (int)); \ + obstack_int_grow_fast (__o, datum); }) + +# define obstack_ptr_grow_fast(OBSTACK,aptr) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(const void **) __o1->next_free = (aptr); \ + __o1->next_free += sizeof (const void *); \ + (void) 0; }) + +# define obstack_int_grow_fast(OBSTACK,aint) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(int *) __o1->next_free = (aint); \ + __o1->next_free += sizeof (int); \ + (void) 0; }) + +# define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + obstack_blank_fast (__o, __len); \ + (void) 0; }) + +# define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +# define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +# define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *__value = (void *) __o1->object_base; \ + if (__o1->next_free == __value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __PTR_ALIGN (__o1->object_base, __o1->next_free, \ + __o1->alignment_mask); \ + if (__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + __value; }) + +# define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = (char *)__obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +# define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +# define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +# define obstack_empty_p(h) \ + ((h)->chunk->prev == 0 \ + && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \ + (h)->chunk->contents, \ + (h)->alignment_mask)) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ + +# define obstack_make_room(h,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0)) + +# define obstack_grow(h,where,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.tempint), \ + (h)->next_free += (h)->temp.tempint) + +# define obstack_grow0(h,where,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.tempint), \ + (h)->next_free += (h)->temp.tempint, \ + *((h)->next_free)++ = 0) + +# define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + obstack_1grow_fast (h, datum)) + +# define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + obstack_ptr_grow_fast (h, datum)) + +# define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + obstack_int_grow_fast (h, datum)) + +# define obstack_ptr_grow_fast(h,aptr) \ + (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr)) + +# define obstack_int_grow_fast(h,aint) \ + (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint)) + +# define obstack_blank(h,length) \ +( (h)->temp.tempint = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ + obstack_blank_fast (h, (h)->temp.tempint)) + +# define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +# define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_finish(h) \ +( ((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp.tempptr = (h)->object_base, \ + (h)->next_free \ + = __PTR_ALIGN ((h)->object_base, (h)->next_free, \ + (h)->alignment_mask), \ + (((h)->next_free - (char *) (h)->chunk \ + > (h)->chunk_limit - (char *) (h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + (h)->temp.tempptr) + +# define obstack_free(h,obj) \ +( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk, \ + ((((h)->temp.tempint > 0 \ + && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk)) \ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp.tempint + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0))) + +#endif /* not __GNUC__ or not __STDC__ */ + +#ifdef __cplusplus +} /* C++ */ +#endif + +#endif /* obstack.h */ diff --git a/lib/pipe-safer.c b/lib/pipe-safer.c new file mode 100644 index 00000000..fb02d721 --- /dev/null +++ b/lib/pipe-safer.c @@ -0,0 +1,50 @@ +/* Invoke pipe, but avoid some glitches. + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Jim Meyering. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "unistd-safer.h" + +#include <unistd.h> + +/* Like pipe, but ensure that neither of the file descriptors is + STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO. */ + +int +pipe_safer (int fd[2]) +{ + int fail = pipe (fd); + if (fail) + return fail; + + { + int i; + for (i = 0; i < 2; i++) + { + int f = fd_safer (fd[i]); + if (f < 0) + return -1; + fd[i] = f; + } + } + + return 0; +} diff --git a/lib/quote.c b/lib/quote.c new file mode 100644 index 00000000..16cc939c --- /dev/null +++ b/lib/quote.c @@ -0,0 +1,41 @@ +/* quote.c - quote arguments for output + Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "quotearg.h" +#include "quote.h" + +/* Return an unambiguous printable representation of NAME, + allocated in slot N, suitable for diagnostics. */ +char const * +quote_n (int n, char const *name) +{ + return quotearg_n_style (n, locale_quoting_style, name); +} + +/* Return an unambiguous printable representation of NAME, + suitable for diagnostics. */ +char const * +quote (char const *name) +{ + return quote_n (0, name); +} diff --git a/lib/quote.h b/lib/quote.h new file mode 100644 index 00000000..5400eadb --- /dev/null +++ b/lib/quote.h @@ -0,0 +1,22 @@ +/* quote.h - prototypes for quote.c + + Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + + +char const *quote_n (int n, char const *name); +char const *quote (char const *name); diff --git a/lib/quotearg.c b/lib/quotearg.c new file mode 100644 index 00000000..113239fb --- /dev/null +++ b/lib/quotearg.c @@ -0,0 +1,690 @@ +/* quotearg.c - quote arguments for output + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "quotearg.h" + +#include "xalloc.h" + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +#if HAVE_WCHAR_H + +/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */ +# include <stdio.h> +# include <time.h> + +# include <wchar.h> +#endif + +#if !HAVE_MBRTOWC +/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the + other macros are defined only for documentation and to satisfy C + syntax. */ +# undef MB_CUR_MAX +# define MB_CUR_MAX 1 +# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0) +# define iswprint(wc) isprint ((unsigned char) (wc)) +# undef HAVE_MBSINIT +#endif + +#if !defined mbsinit && !HAVE_MBSINIT +# define mbsinit(ps) 1 +#endif + +#ifndef iswprint +# if HAVE_WCTYPE_H +# include <wctype.h> +# endif +# if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +# endif +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +#define INT_BITS (sizeof (int) * CHAR_BIT) + +struct quoting_options +{ + /* Basic quoting style. */ + enum quoting_style style; + + /* Quote the characters indicated by this bit vector even if the + quoting style would not normally require them to be quoted. */ + unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1]; +}; + +/* Names of quoting styles. */ +char const *const quoting_style_args[] = +{ + "literal", + "shell", + "shell-always", + "c", + "escape", + "locale", + "clocale", + 0 +}; + +/* Correspondences to quoting style names. */ +enum quoting_style const quoting_style_vals[] = +{ + literal_quoting_style, + shell_quoting_style, + shell_always_quoting_style, + c_quoting_style, + escape_quoting_style, + locale_quoting_style, + clocale_quoting_style +}; + +/* The default quoting options. */ +static struct quoting_options default_quoting_options; + +/* Allocate a new set of quoting options, with contents initially identical + to O if O is not null, or to the default if O is null. + It is the caller's responsibility to free the result. */ +struct quoting_options * +clone_quoting_options (struct quoting_options *o) +{ + int e = errno; + struct quoting_options *p = xmalloc (sizeof *p); + *p = *(o ? o : &default_quoting_options); + errno = e; + return p; +} + +/* Get the value of O's quoting style. If O is null, use the default. */ +enum quoting_style +get_quoting_style (struct quoting_options *o) +{ + return (o ? o : &default_quoting_options)->style; +} + +/* In O (or in the default if O is null), + set the value of the quoting style to S. */ +void +set_quoting_style (struct quoting_options *o, enum quoting_style s) +{ + (o ? o : &default_quoting_options)->style = s; +} + +/* In O (or in the default if O is null), + set the value of the quoting options for character C to I. + Return the old value. Currently, the only values defined for I are + 0 (the default) and 1 (which means to quote the character even if + it would not otherwise be quoted). */ +int +set_char_quoting (struct quoting_options *o, char c, int i) +{ + unsigned char uc = c; + unsigned int *p = + (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS; + int shift = uc % INT_BITS; + int r = (*p >> shift) & 1; + *p ^= ((i & 1) ^ r) << shift; + return r; +} + +/* MSGID approximates a quotation mark. Return its translation if it + has one; otherwise, return either it or "\"", depending on S. */ +static char const * +gettext_quote (char const *msgid, enum quoting_style s) +{ + char const *translation = _(msgid); + if (translation == msgid && s == clocale_quoting_style) + translation = "\""; + return translation; +} + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using QUOTING_STYLE and the + non-quoting-style part of O to control quoting. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE. + + This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG, + ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting + style specified by O, and O may not be null. */ + +static size_t +quotearg_buffer_restyled (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + enum quoting_style quoting_style, + struct quoting_options const *o) +{ + size_t i; + size_t len = 0; + char const *quote_string = 0; + size_t quote_string_len = 0; + bool backslash_escapes = false; + bool unibyte_locale = MB_CUR_MAX == 1; + +#define STORE(c) \ + do \ + { \ + if (len < buffersize) \ + buffer[len] = (c); \ + len++; \ + } \ + while (0) + + switch (quoting_style) + { + case c_quoting_style: + STORE ('"'); + backslash_escapes = true; + quote_string = "\""; + quote_string_len = 1; + break; + + case escape_quoting_style: + backslash_escapes = true; + break; + + case locale_quoting_style: + case clocale_quoting_style: + { + /* TRANSLATORS: + Get translations for open and closing quotation marks. + + The message catalog should translate "`" to a left + quotation mark suitable for the locale, and similarly for + "'". If the catalog has no translation, + locale_quoting_style quotes `like this', and + clocale_quoting_style quotes "like this". + + For example, an American English Unicode locale should + translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and + should translate "'" to U+201D (RIGHT DOUBLE QUOTATION + MARK). A British English Unicode locale should instead + translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and + U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. + + If you don't know what to put here, please see + <http://en.wikipedia.org/wiki/Quotation_mark#Glyphs> + and use glyphs suitable for your language. */ + + char const *left = gettext_quote (N_("`"), quoting_style); + char const *right = gettext_quote (N_("'"), quoting_style); + for (quote_string = left; *quote_string; quote_string++) + STORE (*quote_string); + backslash_escapes = true; + quote_string = right; + quote_string_len = strlen (quote_string); + } + break; + + case shell_always_quoting_style: + STORE ('\''); + quote_string = "'"; + quote_string_len = 1; + break; + + default: + break; + } + + for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++) + { + unsigned char c; + unsigned char esc; + + if (backslash_escapes + && quote_string_len + && i + quote_string_len <= argsize + && memcmp (arg + i, quote_string, quote_string_len) == 0) + STORE ('\\'); + + c = arg[i]; + switch (c) + { + case '\0': + if (backslash_escapes) + { + STORE ('\\'); + STORE ('0'); + STORE ('0'); + c = '0'; + } + break; + + case '?': + switch (quoting_style) + { + case shell_quoting_style: + goto use_shell_always_quoting_style; + + case c_quoting_style: + if (i + 2 < argsize && arg[i + 1] == '?') + switch (arg[i + 2]) + { + case '!': case '\'': + case '(': case ')': case '-': case '/': + case '<': case '=': case '>': + /* Escape the second '?' in what would otherwise be + a trigraph. */ + c = arg[i + 2]; + i += 2; + STORE ('?'); + STORE ('\\'); + STORE ('?'); + break; + + default: + break; + } + break; + + default: + break; + } + break; + + case '\a': esc = 'a'; goto c_escape; + case '\b': esc = 'b'; goto c_escape; + case '\f': esc = 'f'; goto c_escape; + case '\n': esc = 'n'; goto c_and_shell_escape; + case '\r': esc = 'r'; goto c_and_shell_escape; + case '\t': esc = 't'; goto c_and_shell_escape; + case '\v': esc = 'v'; goto c_escape; + case '\\': esc = c; goto c_and_shell_escape; + + c_and_shell_escape: + if (quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + c_escape: + if (backslash_escapes) + { + c = esc; + goto store_escape; + } + break; + + case '{': case '}': /* sometimes special if isolated */ + if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1)) + break; + /* Fall through. */ + case '#': case '~': + if (i != 0) + break; + /* Fall through. */ + case ' ': + case '!': /* special in bash */ + case '"': case '$': case '&': + case '(': case ')': case '*': case ';': + case '<': + case '=': /* sometimes special in 0th or (with "set -k") later args */ + case '>': case '[': + case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */ + case '`': case '|': + /* A shell special character. In theory, '$' and '`' could + be the first bytes of multibyte characters, which means + we should check them with mbrtowc, but in practice this + doesn't happen so it's not worth worrying about. */ + if (quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + break; + + case '\'': + switch (quoting_style) + { + case shell_quoting_style: + goto use_shell_always_quoting_style; + + case shell_always_quoting_style: + STORE ('\''); + STORE ('\\'); + STORE ('\''); + break; + + default: + break; + } + break; + + case '%': case '+': case ',': case '-': case '.': case '/': + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case ':': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': case ']': case '_': case 'a': case 'b': + case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': + case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': + /* These characters don't cause problems, no matter what the + quoting style is. They cannot start multibyte sequences. */ + break; + + default: + /* If we have a multibyte sequence, copy it until we reach + its end, find an error, or come back to the initial shift + state. For C-like styles, if the sequence has + unprintable characters, escape the whole sequence, since + we can't easily escape single characters within it. */ + { + /* Length of multibyte sequence found so far. */ + size_t m; + + bool printable; + + if (unibyte_locale) + { + m = 1; + printable = isprint (c) != 0; + } + else + { + mbstate_t mbstate; + memset (&mbstate, 0, sizeof mbstate); + + m = 0; + printable = true; + if (argsize == SIZE_MAX) + argsize = strlen (arg); + + do + { + wchar_t w; + size_t bytes = mbrtowc (&w, &arg[i + m], + argsize - (i + m), &mbstate); + if (bytes == 0) + break; + else if (bytes == (size_t) -1) + { + printable = false; + break; + } + else if (bytes == (size_t) -2) + { + printable = false; + while (i + m < argsize && arg[i + m]) + m++; + break; + } + else + { + /* Work around a bug with older shells that "see" a '\' + that is really the 2nd byte of a multibyte character. + In practice the problem is limited to ASCII + chars >= '@' that are shell special chars. */ + if ('[' == 0x5b && quoting_style == shell_quoting_style) + { + size_t j; + for (j = 1; j < bytes; j++) + switch (arg[i + m + j]) + { + case '[': case '\\': case '^': + case '`': case '|': + goto use_shell_always_quoting_style; + + default: + break; + } + } + + if (! iswprint (w)) + printable = false; + m += bytes; + } + } + while (! mbsinit (&mbstate)); + } + + if (1 < m || (backslash_escapes && ! printable)) + { + /* Output a multibyte sequence, or an escaped + unprintable unibyte character. */ + size_t ilim = i + m; + + for (;;) + { + if (backslash_escapes && ! printable) + { + STORE ('\\'); + STORE ('0' + (c >> 6)); + STORE ('0' + ((c >> 3) & 7)); + c = '0' + (c & 7); + } + if (ilim <= i + 1) + break; + STORE (c); + c = arg[++i]; + } + + goto store_c; + } + } + } + + if (! (backslash_escapes + && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))) + goto store_c; + + store_escape: + STORE ('\\'); + + store_c: + STORE (c); + } + + if (i == 0 && quoting_style == shell_quoting_style) + goto use_shell_always_quoting_style; + + if (quote_string) + for (; *quote_string; quote_string++) + STORE (*quote_string); + + if (len < buffersize) + buffer[len] = '\0'; + return len; + + use_shell_always_quoting_style: + return quotearg_buffer_restyled (buffer, buffersize, arg, argsize, + shell_always_quoting_style, o); +} + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using O to control quoting. + If O is null, use the default. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is SIZE_MAX, use the string length of the argument for + ARGSIZE. */ +size_t +quotearg_buffer (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + struct quoting_options const *o) +{ + struct quoting_options const *p = o ? o : &default_quoting_options; + int e = errno; + size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize, + p->style, p); + errno = e; + return r; +} + +/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly + allocated storage containing the quoted string. */ +char * +quotearg_alloc (char const *arg, size_t argsize, + struct quoting_options const *o) +{ + int e = errno; + size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1; + char *buf = xmalloc (bufsize); + quotearg_buffer (buf, bufsize, arg, argsize, o); + errno = e; + return buf; +} + +/* Use storage slot N to return a quoted version of argument ARG. + ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a + null-terminated string. + OPTIONS specifies the quoting options. + The returned value points to static storage that can be + reused by the next call to this function with the same value of N. + N must be nonnegative. N is deliberately declared with type "int" + to allow for future extensions (using negative values). */ +static char * +quotearg_n_options (int n, char const *arg, size_t argsize, + struct quoting_options const *options) +{ + int e = errno; + + /* Preallocate a slot 0 buffer, so that the caller can always quote + one small component of a "memory exhausted" message in slot 0. */ + static char slot0[256]; + static unsigned int nslots = 1; + unsigned int n0 = n; + struct slotvec + { + size_t size; + char *val; + }; + static struct slotvec slotvec0 = {sizeof slot0, slot0}; + static struct slotvec *slotvec = &slotvec0; + + if (n < 0) + abort (); + + if (nslots <= n0) + { + /* FIXME: technically, the type of n1 should be `unsigned int', + but that evokes an unsuppressible warning from gcc-4.0.1 and + older. If gcc ever provides an option to suppress that warning, + revert to the original type, so that the test in xalloc_oversized + is once again performed only at compile time. */ + size_t n1 = n0 + 1; + + if (xalloc_oversized (n1, sizeof *slotvec)) + xalloc_die (); + + if (slotvec == &slotvec0) + { + slotvec = xmalloc (sizeof *slotvec); + *slotvec = slotvec0; + } + slotvec = xrealloc (slotvec, n1 * sizeof *slotvec); + memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec); + nslots = n1; + } + + { + size_t size = slotvec[n].size; + char *val = slotvec[n].val; + size_t qsize = quotearg_buffer (val, size, arg, argsize, options); + + if (size <= qsize) + { + slotvec[n].size = size = qsize + 1; + if (val != slot0) + free (val); + slotvec[n].val = val = xmalloc (size); + quotearg_buffer (val, size, arg, argsize, options); + } + + errno = e; + return val; + } +} + +char * +quotearg_n (int n, char const *arg) +{ + return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options); +} + +char * +quotearg (char const *arg) +{ + return quotearg_n (0, arg); +} + +/* Return quoting options for STYLE, with no extra quoting. */ +static struct quoting_options +quoting_options_from_style (enum quoting_style style) +{ + struct quoting_options o; + o.style = style; + memset (o.quote_these_too, 0, sizeof o.quote_these_too); + return o; +} + +char * +quotearg_n_style (int n, enum quoting_style s, char const *arg) +{ + struct quoting_options const o = quoting_options_from_style (s); + return quotearg_n_options (n, arg, SIZE_MAX, &o); +} + +char * +quotearg_n_style_mem (int n, enum quoting_style s, + char const *arg, size_t argsize) +{ + struct quoting_options const o = quoting_options_from_style (s); + return quotearg_n_options (n, arg, argsize, &o); +} + +char * +quotearg_style (enum quoting_style s, char const *arg) +{ + return quotearg_n_style (0, s, arg); +} + +char * +quotearg_char (char const *arg, char ch) +{ + struct quoting_options options; + options = default_quoting_options; + set_char_quoting (&options, ch, 1); + return quotearg_n_options (0, arg, SIZE_MAX, &options); +} + +char * +quotearg_colon (char const *arg) +{ + return quotearg_char (arg, ':'); +} diff --git a/lib/quotearg.h b/lib/quotearg.h new file mode 100644 index 00000000..24f26f7d --- /dev/null +++ b/lib/quotearg.h @@ -0,0 +1,137 @@ +/* quotearg.h - quote arguments for output + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> */ + +#ifndef QUOTEARG_H_ +# define QUOTEARG_H_ 1 + +# include <stddef.h> + +/* Basic quoting styles. */ +enum quoting_style + { + /* Output names as-is (ls --quoting-style=literal). */ + literal_quoting_style, + + /* Quote names for the shell if they contain shell metacharacters + or would cause ambiguous output (ls --quoting-style=shell). */ + shell_quoting_style, + + /* Quote names for the shell, even if they would normally not + require quoting (ls --quoting-style=shell-always). */ + shell_always_quoting_style, + + /* Quote names as for a C language string (ls --quoting-style=c). */ + c_quoting_style, + + /* Like c_quoting_style except omit the surrounding double-quote + characters (ls --quoting-style=escape). */ + escape_quoting_style, + + /* Like clocale_quoting_style, but quote `like this' instead of + "like this" in the default C locale (ls --quoting-style=locale). */ + locale_quoting_style, + + /* Like c_quoting_style except use quotation marks appropriate for + the locale (ls --quoting-style=clocale). */ + clocale_quoting_style + }; + +/* For now, --quoting-style=literal is the default, but this may change. */ +# ifndef DEFAULT_QUOTING_STYLE +# define DEFAULT_QUOTING_STYLE literal_quoting_style +# endif + +/* Names of quoting styles and their corresponding values. */ +extern char const *const quoting_style_args[]; +extern enum quoting_style const quoting_style_vals[]; + +struct quoting_options; + +/* The functions listed below set and use a hidden variable + that contains the default quoting style options. */ + +/* Allocate a new set of quoting options, with contents initially identical + to O if O is not null, or to the default if O is null. + It is the caller's responsibility to free the result. */ +struct quoting_options *clone_quoting_options (struct quoting_options *o); + +/* Get the value of O's quoting style. If O is null, use the default. */ +enum quoting_style get_quoting_style (struct quoting_options *o); + +/* In O (or in the default if O is null), + set the value of the quoting style to S. */ +void set_quoting_style (struct quoting_options *o, enum quoting_style s); + +/* In O (or in the default if O is null), + set the value of the quoting options for character C to I. + Return the old value. Currently, the only values defined for I are + 0 (the default) and 1 (which means to quote the character even if + it would not otherwise be quoted). */ +int set_char_quoting (struct quoting_options *o, char c, int i); + +/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of + argument ARG (of size ARGSIZE), using O to control quoting. + If O is null, use the default. + Terminate the output with a null character, and return the written + size of the output, not counting the terminating null. + If BUFFERSIZE is too small to store the output string, return the + value that would have been returned had BUFFERSIZE been large enough. + If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */ +size_t quotearg_buffer (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + struct quoting_options const *o); + +/* Like quotearg_buffer, except return the result in a newly allocated + buffer. It is the caller's responsibility to free the result. */ +char *quotearg_alloc (char const *arg, size_t argsize, + struct quoting_options const *o); + +/* Use storage slot N to return a quoted version of the string ARG. + Use the default quoting options. + The returned value points to static storage that can be + reused by the next call to this function with the same value of N. + N must be nonnegative. */ +char *quotearg_n (int n, char const *arg); + +/* Equivalent to quotearg_n (0, ARG). */ +char *quotearg (char const *arg); + +/* Use style S and storage slot N to return a quoted version of the string ARG. + This is like quotearg_n (N, ARG), except that it uses S with no other + options to specify the quoting method. */ +char *quotearg_n_style (int n, enum quoting_style s, char const *arg); + +/* Use style S and storage slot N to return a quoted version of the + argument ARG of size ARGSIZE. This is like quotearg_n_style + (N, S, ARG), except it can quote null bytes. */ +char *quotearg_n_style_mem (int n, enum quoting_style s, + char const *arg, size_t argsize); + +/* Equivalent to quotearg_n_style (0, S, ARG). */ +char *quotearg_style (enum quoting_style s, char const *arg); + +/* Like quotearg (ARG), except also quote any instances of CH. */ +char *quotearg_char (char const *arg, char ch); + +/* Equivalent to quotearg_char (ARG, ':'). */ +char *quotearg_colon (char const *arg); + +#endif /* !QUOTEARG_H_ */ diff --git a/lib/stdbool_.h b/lib/stdbool_.h new file mode 100644 index 00000000..efa80ba9 --- /dev/null +++ b/lib/stdbool_.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + Written by Bruno Haible <haible@clisp.cons.org>, 2001. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _STDBOOL_H +#define _STDBOOL_H + +/* ISO C 99 <stdbool.h> for platforms that lack it. */ + +/* Usage suggestions: + + Programs that use <stdbool.h> should be aware of some limitations + and standards compliance issues. + + Standards compliance: + + - <stdbool.h> must be #included before 'bool', 'false', 'true' + can be used. + + - You cannot assume that sizeof (bool) == 1. + + - Programs should not undefine the macros bool, true, and false, + as C99 lists that as an "obsolescent feature". + + Limitations of this substitute, when used in a C89 environment: + + - <stdbool.h> must be #included before the '_Bool' type can be used. + + - You cannot assume that _Bool is a typedef; it might be a macro. + + - In C99, casts and automatic conversions to '_Bool' or 'bool' are + performed in such a way that every nonzero value gets converted + to 'true', and zero gets converted to 'false'. This doesn't work + with this substitute. With this substitute, only the values 0 and 1 + give the expected result when converted to _Bool' or 'bool'. + + Also, it is suggested that programs use 'bool' rather than '_Bool'; + this isn't required, but 'bool' is more common. */ + + +/* 7.16. Boolean type and values */ + +/* BeOS <sys/socket.h> already #defines false 0, true 1. We use the same + definitions below, but temporarily we have to #undef them. */ +#ifdef __BEOS__ +# include <OS.h> /* defines bool but not _Bool */ +# undef false +# undef true +#endif + +/* For the sake of symbolic names in gdb, we define true and false as + enum constants, not only as macros. + It is tempting to write + typedef enum { false = 0, true = 1 } _Bool; + so that gdb prints values of type 'bool' symbolically. But if we do + this, values of type '_Bool' may promote to 'int' or 'unsigned int' + (see ISO C 99 6.7.2.2.(4)); however, '_Bool' must promote to 'int' + (see ISO C 99 6.3.1.1.(2)). So we add a negative value to the + enum; this ensures that '_Bool' promotes to 'int'. */ +#if defined __cplusplus || defined __BEOS__ + /* A compiler known to have 'bool'. */ + /* If the compiler already has both 'bool' and '_Bool', we can assume they + are the same types. */ +# if !@HAVE__BOOL@ +typedef bool _Bool; +# endif +#else +# if !defined __GNUC__ + /* If @HAVE__BOOL@: + Some HP-UX cc and AIX IBM C compiler versions have compiler bugs when + the built-in _Bool type is used. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html + Similar bugs are likely with other compilers as well; this file + wouldn't be used if <stdbool.h> was working. + So we override the _Bool type. + If !@HAVE__BOOL@: + Need to define _Bool ourselves. As 'signed char' or as an enum type? + Use of a typedef, with SunPRO C, leads to a stupid + "warning: _Bool is a keyword in ISO C99". + Use of an enum type, with IRIX cc, leads to a stupid + "warning(1185): enumerated type mixed with another type". + The only benefit of the enum type, debuggability, is not important + with these compilers. So use 'signed char' and no typedef. */ +# define _Bool signed char +enum { false = 0, true = 1 }; +# else + /* With this compiler, trust the _Bool type if the compiler has it. */ +# if !@HAVE__BOOL@ +typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool; +# endif +# endif +#endif +#define bool _Bool + +/* The other macros must be usable in preprocessor directives. */ +#define false 0 +#define true 1 +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H */ diff --git a/lib/stdio--.h b/lib/stdio--.h new file mode 100644 index 00000000..b2765fd5 --- /dev/null +++ b/lib/stdio--.h @@ -0,0 +1,25 @@ +/* Like stdio.h, but redefine some names to avoid glitches. + + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#include <stdio.h> +#include "stdio-safer.h" + +#undef fopen +#define fopen fopen_safer diff --git a/lib/stdio-safer.h b/lib/stdio-safer.h new file mode 100644 index 00000000..0b9a9ab8 --- /dev/null +++ b/lib/stdio-safer.h @@ -0,0 +1,23 @@ +/* Invoke stdio functions, but avoid some glitches. + + Copyright (C) 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#include <stdio.h> + +FILE *fopen_safer (char const *, char const *); diff --git a/lib/stpcpy.c b/lib/stpcpy.c new file mode 100644 index 00000000..acda21a2 --- /dev/null +++ b/lib/stpcpy.c @@ -0,0 +1,50 @@ +/* stpcpy.c -- copy a string and return pointer to end of new string + Copyright (C) 1992, 1995, 1997, 1998 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#undef __stpcpy +#undef stpcpy + +#ifndef weak_alias +# define __stpcpy stpcpy +#endif + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +__stpcpy (char *dest, const char *src) +{ + register char *d = dest; + register const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} +#ifdef weak_alias +weak_alias (__stpcpy, stpcpy) +#endif diff --git a/lib/stpcpy.h b/lib/stpcpy.h new file mode 100644 index 00000000..53c4ce00 --- /dev/null +++ b/lib/stpcpy.h @@ -0,0 +1,41 @@ +/* String copying. + Copyright (C) 1995, 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _STPCPY_H +#define _STPCPY_H + +#if HAVE_STPCPY + +/* Get stpcpy() declaration. */ +#include <string.h> + +#else + +#ifdef __cplusplus +extern "C" { +#endif + +/* Copy SRC to DST, returning the address of the terminating '\0' in DST. */ +extern char *stpcpy (char *dst, const char *src); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* _STPCPY_H */ diff --git a/lib/strdup.c b/lib/strdup.c new file mode 100644 index 00000000..d6d01162 --- /dev/null +++ b/lib/strdup.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991, 1996, 1997, 1998, 2002, 2003, 2004 Free Software + Foundation, Inc. + + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef _LIBC +/* Get specification. */ +# include "strdup.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#undef __strdup +#undef strdup + +#ifndef weak_alias +# define __strdup strdup +#endif + +/* Duplicate S, returning an identical malloc'd string. */ +char * +__strdup (const char *s) +{ + size_t len = strlen (s) + 1; + void *new = malloc (len); + + if (new == NULL) + return NULL; + + return (char *) memcpy (new, s, len); +} +#ifdef libc_hidden_def +libc_hidden_def (__strdup) +#endif +#ifdef weak_alias +weak_alias (__strdup, strdup) +#endif diff --git a/lib/strdup.h b/lib/strdup.h new file mode 100644 index 00000000..a0d5fb92 --- /dev/null +++ b/lib/strdup.h @@ -0,0 +1,29 @@ +/* strdup.h -- duplicate a string + Copyright (C) 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef STRDUP_H_ +#define STRDUP_H_ + +/* Get strdup declaration, if available. */ +#include <string.h> + +#if defined HAVE_DECL_STRDUP && !HAVE_DECL_STRDUP && !defined strdup +/* Duplicate S, returning an identical malloc'd string. */ +extern char *strdup (const char *s); +#endif + +#endif /* STRDUP_H_ */ diff --git a/lib/strerror.c b/lib/strerror.c new file mode 100644 index 00000000..623821d2 --- /dev/null +++ b/lib/strerror.c @@ -0,0 +1,49 @@ +/* strerror.c --- ANSI C compatible system error routine + + Copyright (C) 1986, 1988, 1989, 1991, 2002, 2003 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <limits.h> + +/* Don't include <stdio.h>, since it may or may not declare + sys_errlist and its declarations may collide with ours. Just + declare the stuff that we need directly. Standard hosted C89 + implementations define strerror and they don't need this strerror + function, so take some liberties with the standard to cater to + ancient or limited freestanding implementations. */ +int sprintf (char *, char const *, ...); +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror (int n) +{ + static char const fmt[] = "Unknown error (%d)"; + static char mesg[sizeof fmt + sizeof n * CHAR_BIT / 3]; + + if (n < 0 || n >= sys_nerr) + { + sprintf (mesg, fmt, n); + return mesg; + } + else + return sys_errlist[n]; +} diff --git a/lib/stripslash.c b/lib/stripslash.c new file mode 100644 index 00000000..9b55da48 --- /dev/null +++ b/lib/stripslash.c @@ -0,0 +1,40 @@ +/* stripslash.c -- remove redundant trailing slashes from a file name + + Copyright (C) 1990, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" + +/* Remove trailing slashes from FILE. + Return true if a trailing slash was removed. + This is useful when using file name completion from a shell that + adds a "/" after directory names (such as tcsh and bash), because + the Unix rename and rmdir system calls return an "Invalid argument" error + when given a file that ends in "/" (except for the root directory). */ + +bool +strip_trailing_slashes (char *file) +{ + char *base = base_name (file); + char *base_lim = base + base_len (base); + bool had_slash = (*base_lim != '\0'); + *base_lim = '\0'; + return had_slash; +} diff --git a/lib/strndup.c b/lib/strndup.c new file mode 100644 index 00000000..2626373f --- /dev/null +++ b/lib/strndup.c @@ -0,0 +1,66 @@ +/* Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2005, 2006 Free + Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#if !_LIBC +# include "strndup.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#if !_LIBC +# include "strnlen.h" +# ifndef __strnlen +# define __strnlen strnlen +# endif +#endif + +#undef __strndup +#if _LIBC +# undef strndup +#endif + +#ifndef weak_alias +# define __strndup strndup +#endif + +char * +__strndup (s, n) + const char *s; + size_t n; +{ + size_t len = __strnlen (s, n); + char *new = malloc (len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return memcpy (new, s, len); +} +#ifdef libc_hidden_def +libc_hidden_def (__strndup) +#endif +#ifdef weak_alias +weak_alias (__strndup, strndup) +#endif diff --git a/lib/strndup.h b/lib/strndup.h new file mode 100644 index 00000000..8eae493a --- /dev/null +++ b/lib/strndup.h @@ -0,0 +1,30 @@ +/* Duplicate a size-bounded string. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#if HAVE_STRNDUP + +/* Get strndup() declaration. */ +#include <string.h> + +#else + +#include <stddef.h> + +/* Return a newly allocated copy of at most N bytes of STRING. */ +extern char *strndup (const char *string, size_t n); + +#endif diff --git a/lib/strnlen.c b/lib/strnlen.c new file mode 100644 index 00000000..09ba788a --- /dev/null +++ b/lib/strnlen.c @@ -0,0 +1,33 @@ +/* Find the length of STRING, but scan at most MAXLEN characters. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "strnlen.h" + +/* Find the length of STRING, but scan at most MAXLEN characters. + If no '\0' terminator is found in that many characters, return MAXLEN. */ + +size_t +strnlen (const char *string, size_t maxlen) +{ + const char *end = memchr (string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} diff --git a/lib/strnlen.h b/lib/strnlen.h new file mode 100644 index 00000000..ba74dba7 --- /dev/null +++ b/lib/strnlen.h @@ -0,0 +1,32 @@ +/* Find the length of STRING, but scan at most MAXLEN characters. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef STRNLEN_H +#define STRNLEN_H + +/* Get strnlen declaration, if available. */ +#include <string.h> + +#if defined HAVE_DECL_STRNLEN && !HAVE_DECL_STRNLEN +/* Find the length (number of bytes) of STRING, but scan at most + MAXLEN bytes. If no '\0' terminator is found in that many bytes, + return MAXLEN. */ +extern size_t strnlen(const char *string, size_t maxlen); +#endif + +#endif /* STRNLEN_H */ diff --git a/lib/strtol.c b/lib/strtol.c new file mode 100644 index 00000000..9bfbe3c1 --- /dev/null +++ b/lib/strtol.c @@ -0,0 +1,447 @@ +/* Convert string representation of a number into an integer value. + + Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2003, 2005 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# define USE_NUMBER_GROUPING +#endif + +#include <ctype.h> +#include <errno.h> +#ifndef errno +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#ifdef USE_NUMBER_GROUPING +# include "../locale/localeinfo.h" +#endif + +/* Nonzero if we are defining `strtoul' or `strtoull', operating on + unsigned integers. */ +#ifndef UNSIGNED +# define UNSIGNED 0 +# define INT LONG int +#else +# define INT unsigned LONG int +#endif + +/* Determine the name. */ +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# if UNSIGNED +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol __wcstoull_l +# else +# define strtol __wcstoul_l +# endif +# else +# ifdef QUAD +# define strtol __strtoull_l +# else +# define strtol __strtoul_l +# endif +# endif +# else +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol __wcstoll_l +# else +# define strtol __wcstol_l +# endif +# else +# ifdef QUAD +# define strtol __strtoll_l +# else +# define strtol __strtol_l +# endif +# endif +# endif +#else +# if UNSIGNED +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol wcstoull +# else +# define strtol wcstoul +# endif +# else +# ifdef QUAD +# define strtol strtoull +# else +# define strtol strtoul +# endif +# endif +# else +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol wcstoll +# else +# define strtol wcstol +# endif +# else +# ifdef QUAD +# define strtol strtoll +# endif +# endif +# endif +#endif + +/* If QUAD is defined, we are defining `strtoll' or `strtoull', + operating on `long long int's. */ +#ifdef QUAD +# define LONG long long +# define STRTOL_LONG_MIN LONG_LONG_MIN +# define STRTOL_LONG_MAX LONG_LONG_MAX +# define STRTOL_ULONG_MAX ULONG_LONG_MAX + +/* The extra casts in the following macros work around compiler bugs, + e.g., in Cray C 5.0.3.0. */ + +/* True if negative values of the signed integer type T use two's + complement, ones' complement, or signed magnitude representation, + respectively. Much GNU code assumes two's complement, but some + people like to be portable to all possible C hosts. */ +# define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1) +# define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0) +# define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1) + +/* True if the arithmetic type T is signed. */ +# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* The maximum and minimum values for the integer type T. These + macros have undefined behavior if T is signed and has padding bits. + If this is a problem for you, please let us know how to fix it for + your host. */ +# define TYPE_MINIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) 0 \ + : TYPE_SIGNED_MAGNITUDE (t) \ + ? ~ (t) 0 \ + : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))) +# define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) + +# ifndef ULONG_LONG_MAX +# define ULONG_LONG_MAX TYPE_MAXIMUM (unsigned long long) +# endif +# ifndef LONG_LONG_MAX +# define LONG_LONG_MAX TYPE_MAXIMUM (long long int) +# endif +# ifndef LONG_LONG_MIN +# define LONG_LONG_MIN TYPE_MINIMUM (long long int) +# endif + +# if __GNUC__ == 2 && __GNUC_MINOR__ < 7 + /* Work around gcc bug with using this constant. */ + static const unsigned long long int maxquad = ULONG_LONG_MAX; +# undef STRTOL_ULONG_MAX +# define STRTOL_ULONG_MAX maxquad +# endif +#else +# define LONG long +# define STRTOL_LONG_MIN LONG_MIN +# define STRTOL_LONG_MAX LONG_MAX +# define STRTOL_ULONG_MAX ULONG_MAX +#endif + + +/* We use this code also for the extended locale handling where the + function gets as an additional argument the locale which has to be + used. To access the values we have to redefine the _NL_CURRENT + macro. */ +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# undef _NL_CURRENT +# define _NL_CURRENT(category, item) \ + (current->values[_NL_ITEM_INDEX (item)].string) +# define LOCALE_PARAM , loc +# define LOCALE_PARAM_PROTO , __locale_t loc +#else +# define LOCALE_PARAM +# define LOCALE_PARAM_PROTO +#endif + +#if defined _LIBC || defined HAVE_WCHAR_H +# include <wchar.h> +#endif + +#ifdef USE_WIDE_CHAR +# include <wctype.h> +# define L_(Ch) L##Ch +# define UCHAR_TYPE wint_t +# define STRING_TYPE wchar_t +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define ISSPACE(Ch) __iswspace_l ((Ch), loc) +# define ISALPHA(Ch) __iswalpha_l ((Ch), loc) +# define TOUPPER(Ch) __towupper_l ((Ch), loc) +# else +# define ISSPACE(Ch) iswspace (Ch) +# define ISALPHA(Ch) iswalpha (Ch) +# define TOUPPER(Ch) towupper (Ch) +# endif +#else +# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) 1 +# else +# define IN_CTYPE_DOMAIN(c) isascii(c) +# endif +# define L_(Ch) Ch +# define UCHAR_TYPE unsigned char +# define STRING_TYPE char +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define ISSPACE(Ch) __isspace_l ((Ch), loc) +# define ISALPHA(Ch) __isalpha_l ((Ch), loc) +# define TOUPPER(Ch) __toupper_l ((Ch), loc) +# else +# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch)) +# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch)) +# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch)) +# endif +#endif + +#define INTERNAL(X) INTERNAL1(X) +#define INTERNAL1(X) __##X##_internal +#define WEAKNAME(X) WEAKNAME1(X) + +#ifdef USE_NUMBER_GROUPING +/* This file defines a function to check for correct grouping. */ +# include "grouping.h" +#endif + + + +/* Convert NPTR to an `unsigned long int' or `long int' in base BASE. + If BASE is 0 the base is determined by the presence of a leading + zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. + If BASE is < 2 or > 36, it is reset to 10. + If ENDPTR is not NULL, a pointer to the character after the last + one converted is stored in *ENDPTR. */ + +INT +INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr, + int base, int group LOCALE_PARAM_PROTO) +{ + int negative; + register unsigned LONG int cutoff; + register unsigned int cutlim; + register unsigned LONG int i; + register const STRING_TYPE *s; + register UCHAR_TYPE c; + const STRING_TYPE *save, *end; + int overflow; + +#ifdef USE_NUMBER_GROUPING +# ifdef USE_IN_EXTENDED_LOCALE_MODEL + struct locale_data *current = loc->__locales[LC_NUMERIC]; +# endif + /* The thousands character of the current locale. */ + wchar_t thousands = L'\0'; + /* The numeric grouping specification of the current locale, + in the format described in <locale.h>. */ + const char *grouping; + + if (group) + { + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + if (*grouping <= 0 || *grouping == CHAR_MAX) + grouping = NULL; + else + { + /* Figure out the thousands separator character. */ +# if defined _LIBC || defined _HAVE_BTOWC + thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP)); + if (thousands == WEOF) + thousands = L'\0'; +# endif + if (thousands == L'\0') + grouping = NULL; + } + } + else + grouping = NULL; +#endif + + if (base < 0 || base == 1 || base > 36) + { + __set_errno (EINVAL); + return 0; + } + + save = s = nptr; + + /* Skip white space. */ + while (ISSPACE (*s)) + ++s; + if (*s == L_('\0')) + goto noconv; + + /* Check for a sign. */ + if (*s == L_('-')) + { + negative = 1; + ++s; + } + else if (*s == L_('+')) + { + negative = 0; + ++s; + } + else + negative = 0; + + /* Recognize number prefix and if BASE is zero, figure it out ourselves. */ + if (*s == L_('0')) + { + if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X')) + { + s += 2; + base = 16; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + +#ifdef USE_NUMBER_GROUPING + if (group) + { + /* Find the end of the digit string and check its grouping. */ + end = s; + for (c = *end; c != L_('\0'); c = *++end) + if ((wchar_t) c != thousands + && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9')) + && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base)) + break; + if (*s == thousands) + end = s; + else + end = correctly_grouped_prefix (s, end, thousands, grouping); + } + else +#endif + end = NULL; + + cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base; + cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base; + + overflow = 0; + i = 0; + for (c = *s; c != L_('\0'); c = *++s) + { + if (s == end) + break; + if (c >= L_('0') && c <= L_('9')) + c -= L_('0'); + else if (ISALPHA (c)) + c = TOUPPER (c) - L_('A') + 10; + else + break; + if ((int) c >= base) + break; + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned LONG int) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (STRING_TYPE *) s; + +#if !UNSIGNED + /* Check for a value that is within the range of + `unsigned LONG int', but outside the range of `LONG int'. */ + if (overflow == 0 + && i > (negative + ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1 + : (unsigned LONG int) STRTOL_LONG_MAX)) + overflow = 1; +#endif + + if (overflow) + { + __set_errno (ERANGE); +#if UNSIGNED + return STRTOL_ULONG_MAX; +#else + return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX; +#endif + } + + /* Return the result of the appropriate sign. */ + return negative ? -i : i; + +noconv: + /* We must handle a special case here: the base is 0 or 16 and the + first two characters are '0' and 'x', but the rest are no + hexadecimal digits. This is no error case. We return 0 and + ENDPTR points to the `x`. */ + if (endptr != NULL) + { + if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X') + && save[-2] == L_('0')) + *endptr = (STRING_TYPE *) &save[-1]; + else + /* There was no number to convert. */ + *endptr = (STRING_TYPE *) nptr; + } + + return 0L; +} + +/* External user entry point. */ + + +INT +#ifdef weak_function +weak_function +#endif +strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr, + int base LOCALE_PARAM_PROTO) +{ + return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM); +} diff --git a/lib/strtoul.c b/lib/strtoul.c new file mode 100644 index 00000000..79ceed2f --- /dev/null +++ b/lib/strtoul.c @@ -0,0 +1,20 @@ +/* Copyright (C) 1991, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define UNSIGNED 1 + +#include "strtol.c" diff --git a/lib/strverscmp.c b/lib/strverscmp.c new file mode 100644 index 00000000..6276bca0 --- /dev/null +++ b/lib/strverscmp.c @@ -0,0 +1,131 @@ +/* Compare strings while treating digits characters numerically. + Copyright (C) 1997, 2000, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <ctype.h> + +/* states: S_N: normal, S_I: comparing integral part, S_F: comparing + fractional parts, S_Z: idem but with leading Zeroes only */ +#define S_N 0x0 +#define S_I 0x4 +#define S_F 0x8 +#define S_Z 0xC + +/* result_type: CMP: return diff; LEN: compare using len_diff/diff */ +#define CMP 2 +#define LEN 3 + + +/* ISDIGIT differs from isdigit, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + ISDIGIT_LOCALE unless it's important to use the locale's definition + of `digit' even when the host does not conform to POSIX. */ +#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) + +#undef __strverscmp +#undef strverscmp + +#ifndef weak_alias +# define __strverscmp strverscmp +#endif + +/* Compare S1 and S2 as strings holding indices/version numbers, + returning less than, equal to or greater than zero if S1 is less than, + equal to or greater than S2 (for more info, see the texinfo doc). +*/ + +int +__strverscmp (const char *s1, const char *s2) +{ + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + int state; + int diff; + + /* Symbol(s) 0 [1-9] others (padding) + Transition (10) 0 (01) d (00) x (11) - */ + static const unsigned int next_state[] = + { + /* state x d 0 - */ + /* S_N */ S_N, S_I, S_Z, S_N, + /* S_I */ S_N, S_I, S_I, S_I, + /* S_F */ S_N, S_F, S_F, S_F, + /* S_Z */ S_N, S_F, S_Z, S_Z + }; + + static const int result_type[] = + { + /* state x/x x/d x/0 x/- d/x d/d d/0 d/- + 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ + + /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_I */ CMP, -1, -1, CMP, 1, LEN, LEN, CMP, + 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, + /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_Z */ CMP, 1, 1, CMP, -1, CMP, CMP, CMP, + -1, CMP, CMP, CMP + }; + + if (p1 == p2) + return 0; + + c1 = *p1++; + c2 = *p2++; + /* Hint: '0' is a digit too. */ + state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0)); + + while ((diff = c1 - c2) == 0 && c1 != '\0') + { + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state |= (c1 == '0') + (ISDIGIT (c1) != 0); + } + + state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))]; + + switch (state) + { + case CMP: + return diff; + + case LEN: + while (ISDIGIT (*p1++)) + if (!ISDIGIT (*p2++)) + return 1; + + return ISDIGIT (*p2) ? -1 : diff; + + default: + return state; + } +} +#ifdef weak_alias +weak_alias (__strverscmp, strverscmp) +#endif diff --git a/lib/strverscmp.h b/lib/strverscmp.h new file mode 100644 index 00000000..7edeac5e --- /dev/null +++ b/lib/strverscmp.h @@ -0,0 +1,24 @@ +/* Compare strings while treating digits characters numerically. + + Copyright (C) 1997, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef STRVERSCMP_H_ +# define STRVERSCMP_H_ + +int strverscmp (const char *, const char *); + +#endif /* not STRVERSCMP_H_ */ diff --git a/lib/subpipe.c b/lib/subpipe.c new file mode 100644 index 00000000..646aa8ec --- /dev/null +++ b/lib/subpipe.c @@ -0,0 +1,186 @@ +/* Subprocesses with pipes. + + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> + and Florian Krohm <florian@edamail.fishkill.ibm.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "subpipe.h" + +#include <errno.h> + +#include <signal.h> +#if ! defined SIGCHLD && defined SIGCLD +# define SIGCHLD SIGCLD +#endif + +#include <stdlib.h> + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#if ! HAVE_DUP2 && ! defined dup2 +# include <fcntl.h> +# define dup2(f, t) (close (t), fcntl (f, F_DUPFD, t)) +#endif + +#if HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#if HAVE_VFORK_H +# include <vfork.h> +#endif +#if ! HAVE_WORKING_VFORK +# define vfork fork +#endif + +#include "error.h" +#include "unistd-safer.h" + +#include "gettext.h" +#define _(Msgid) gettext (Msgid) + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if ! defined __GNUC__ || __GNUC__ < 2 || \ +(__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + + +/* Initialize this module. */ + +void +init_subpipe (void) +{ +#ifdef SIGCHLD + /* System V fork+wait does not work if SIGCHLD is ignored. */ + signal (SIGCHLD, SIG_DFL); +#endif +} + + +/* Create a subprocess that is run as a filter. ARGV is the + NULL-terminated argument vector for the subprocess. Store read and + write file descriptors for communication with the subprocess into + FD[0] and FD[1]: input meant for the process can be written into + FD[0], and output from the process can be read from FD[1]. Return + the subprocess id. + + To avoid deadlock, the invoker must not let incoming data pile up + in FD[1] while writing data to FD[0]. */ + +pid_t +create_subpipe (char const * const *argv, int fd[2]) +{ + int pipe_fd[2]; + int child_fd[2]; + pid_t pid; + + if (pipe (child_fd) != 0 + || (child_fd[0] = fd_safer (child_fd[0])) < 0 + || (fd[0] = fd_safer (child_fd[1])) < 0 + || pipe (pipe_fd) != 0 + || (fd[1] = fd_safer (pipe_fd[0])) < 0 + || (child_fd[1] = fd_safer (pipe_fd[1])) < 0) + error (EXIT_FAILURE, errno, + "pipe"); + + pid = vfork (); + if (pid < 0) + error (EXIT_FAILURE, errno, + "fork"); + + if (! pid) + { + /* Child. */ + close (fd[0]); + close (fd[1]); + dup2 (child_fd[0], STDIN_FILENO); + close (child_fd[0]); + dup2 (child_fd[1], STDOUT_FILENO); + close (child_fd[1]); + + /* The cast to (char **) rather than (char * const *) is needed + for portability to older hosts with a nonstandard prototype + for execvp. */ + execvp (argv[0], (char **) argv); + + _exit (errno == ENOENT ? 127 : 126); + } + + /* Parent. */ + close (child_fd[0]); + close (child_fd[1]); + return pid; +} + + +/* Wait for the subprocess to exit. */ + +void +reap_subpipe (pid_t pid, char const *program) +{ +#if HAVE_WAITPID || defined waitpid + int wstatus; + if (waitpid (pid, &wstatus, 0) < 0) + error (EXIT_FAILURE, errno, + "waitpid"); + else + { + int status = WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : -1; + if (status) + error (EXIT_FAILURE, 0, + _(status == 126 + ? "subsidiary program `%s' could not be invoked" + : status == 127 + ? "subsidiary program `%s' not found" + : status < 0 + ? "subsidiary program `%s' failed" + : "subsidiary program `%s' failed (exit status %d)"), + program, status); + } +#endif +} + +void +end_of_output_subpipe (pid_t pid ATTRIBUTE_UNUSED, + int fd[2] ATTRIBUTE_UNUSED) +{ +} diff --git a/lib/subpipe.h b/lib/subpipe.h new file mode 100644 index 00000000..1083d32e --- /dev/null +++ b/lib/subpipe.h @@ -0,0 +1,28 @@ +/* Subprocesses with pipes. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert <eggert@twinsun.com> + and Florian Krohm <florian@edamail.fishkill.ibm.com>. */ + +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +void init_subpipe (void); +pid_t create_subpipe (char const * const *, int[2]); +void end_of_output_subpipe (pid_t, int[2]); +void reap_subpipe (pid_t, char const *); diff --git a/lib/timevar.c b/lib/timevar.c new file mode 100644 index 00000000..d9b533ce --- /dev/null +++ b/lib/timevar.c @@ -0,0 +1,565 @@ +/* Timing variables for measuring compiler performance. + Copyright (C) 2000, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Alex Samuel <samuel@codesourcery.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if IN_GCC + +#include "system.h" +#include "intl.h" +#include "rtl.h" + +#else + +/* This source file is taken from the GCC source code, with slight + modifications that are under control of the IN_GCC preprocessor + variable. The !IN_GCC part of this file is specific to Bison. */ + +# include "../src/system.h" +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +int timevar_report = 0; + +#endif + + +#ifdef HAVE_SYS_TIMES_H +# include <sys/times.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +#ifndef HAVE_CLOCK_T +typedef int clock_t; +#endif + +#ifndef HAVE_STRUCT_TMS +struct tms +{ + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; +#endif + +#if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE +extern int getrusage (int, struct rusage *); +#endif +#if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES +extern clock_t times (struct tms *); +#endif +#if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK +extern clock_t clock (void); +#endif + +#ifndef RUSAGE_SELF +# define RUSAGE_SELF 0 +#endif + +/* Calculation of scale factor to convert ticks to microseconds. + We mustn't use CLOCKS_PER_SEC except with clock(). */ +#if HAVE_SYSCONF && defined _SC_CLK_TCK +# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */ +#else +# ifdef CLK_TCK +# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */ +# else +# ifdef HZ +# define TICKS_PER_SECOND HZ /* traditional UNIX */ +# else +# define TICKS_PER_SECOND 100 /* often the correct value */ +# endif +# endif +#endif + +/* Prefer times to getrusage to clock (each gives successively less + information). */ +#ifdef HAVE_TIMES +# define USE_TIMES +# define HAVE_USER_TIME +# define HAVE_SYS_TIME +# define HAVE_WALL_TIME +#else +#ifdef HAVE_GETRUSAGE +# define USE_GETRUSAGE +# define HAVE_USER_TIME +# define HAVE_SYS_TIME +#else +#ifdef HAVE_CLOCK +# define USE_CLOCK +# define HAVE_USER_TIME +#endif +#endif +#endif + +/* libc is very likely to have snuck a call to sysconf() into one of + the underlying constants, and that can be very slow, so we have to + precompute them. Whose wonderful idea was it to make all those + _constants_ variable at run time, anyway? */ +#ifdef USE_TIMES +static float ticks_to_msec; +#define TICKS_TO_MSEC (1.0 / TICKS_PER_SECOND) +#endif + +#ifdef USE_CLOCK +static float clocks_to_msec; +#define CLOCKS_TO_MSEC (1.0 / CLOCKS_PER_SEC) +#endif + +#if IN_GCC +#include "flags.h" +#endif +#include "timevar.h" + +/* See timevar.h for an explanation of timing variables. */ + +/* This macro evaluates to nonzero if timing variables are enabled. */ +#define TIMEVAR_ENABLE (timevar_report) + +/* A timing variable. */ + +struct timevar_def +{ + /* Elapsed time for this variable. */ + struct timevar_time_def elapsed; + + /* If this variable is timed independently of the timing stack, + using timevar_start, this contains the start time. */ + struct timevar_time_def start_time; + + /* The name of this timing variable. */ + const char *name; + + /* Non-zero if this timing variable is running as a standalone + timer. */ + unsigned standalone : 1; + + /* Non-zero if this timing variable was ever started or pushed onto + the timing stack. */ + unsigned used : 1; +}; + +/* An element on the timing stack. Elapsed time is attributed to the + topmost timing variable on the stack. */ + +struct timevar_stack_def +{ + /* The timing variable at this stack level. */ + struct timevar_def *timevar; + + /* The next lower timing variable context in the stack. */ + struct timevar_stack_def *next; +}; + +/* Declared timing variables. Constructed from the contents of + timevar.def. */ +static struct timevar_def timevars[TIMEVAR_LAST]; + +/* The top of the timing stack. */ +static struct timevar_stack_def *stack; + +/* A list of unused (i.e. allocated and subsequently popped) + timevar_stack_def instances. */ +static struct timevar_stack_def *unused_stack_instances; + +/* The time at which the topmost element on the timing stack was + pushed. Time elapsed since then is attributed to the topmost + element. */ +static struct timevar_time_def start_time; + +static void get_time (struct timevar_time_def *); +static void timevar_accumulate (struct timevar_time_def *, + struct timevar_time_def *, + struct timevar_time_def *); + +/* Fill the current times into TIME. The definition of this function + also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and + HAVE_WALL_TIME macros. */ + +static void +get_time (now) + struct timevar_time_def *now; +{ + now->user = 0; + now->sys = 0; + now->wall = 0; + + if (!TIMEVAR_ENABLE) + return; + + { +#ifdef USE_TIMES + struct tms tms; + now->wall = times (&tms) * ticks_to_msec; +#if IN_GCC + now->user = tms.tms_utime * ticks_to_msec; + now->sys = tms.tms_stime * ticks_to_msec; +#else + now->user = (tms.tms_utime + tms.tms_cutime) * ticks_to_msec; + now->sys = (tms.tms_stime + tms.tms_cstime) * ticks_to_msec; +#endif +#endif +#ifdef USE_GETRUSAGE + struct rusage rusage; +#if IN_GCC + getrusage (RUSAGE_SELF, &rusage); +#else + getrusage (RUSAGE_CHILDREN, &rusage); +#endif + now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6; + now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6; +#endif +#ifdef USE_CLOCK + now->user = clock () * clocks_to_msec; +#endif + } +} + +/* Add the difference between STOP and START to TIMER. */ + +static void +timevar_accumulate (timer, start, stop) + struct timevar_time_def *timer; + struct timevar_time_def *start; + struct timevar_time_def *stop; +{ + timer->user += stop->user - start->user; + timer->sys += stop->sys - start->sys; + timer->wall += stop->wall - start->wall; +} + +/* Initialize timing variables. */ + +void +init_timevar () +{ + if (!TIMEVAR_ENABLE) + return; + + /* Zero all elapsed times. */ + memset ((void *) timevars, 0, sizeof (timevars)); + + /* Initialize the names of timing variables. */ +#define DEFTIMEVAR(identifier__, name__) \ + timevars[identifier__].name = name__; +#include "timevar.def" +#undef DEFTIMEVAR + +#ifdef USE_TIMES + ticks_to_msec = TICKS_TO_MSEC; +#endif +#ifdef USE_CLOCK + clocks_to_msec = CLOCKS_TO_MSEC; +#endif +} + +/* Push TIMEVAR onto the timing stack. No further elapsed time is + attributed to the previous topmost timing variable on the stack; + subsequent elapsed time is attributed to TIMEVAR, until it is + popped or another element is pushed on top. + + TIMEVAR cannot be running as a standalone timer. */ + +void +timevar_push (timevar) + timevar_id_t timevar; +{ + struct timevar_def *tv = &timevars[timevar]; + struct timevar_stack_def *context; + struct timevar_time_def now; + + if (!TIMEVAR_ENABLE) + return; + + /* Mark this timing variable as used. */ + tv->used = 1; + + /* Can't push a standalone timer. */ + if (tv->standalone) + abort (); + + /* What time is it? */ + get_time (&now); + + /* If the stack isn't empty, attribute the current elapsed time to + the old topmost element. */ + if (stack) + timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); + + /* Reset the start time; from now on, time is attributed to + TIMEVAR. */ + start_time = now; + + /* See if we have a previously-allocated stack instance. If so, + take it off the list. If not, malloc a new one. */ + if (unused_stack_instances != NULL) + { + context = unused_stack_instances; + unused_stack_instances = unused_stack_instances->next; + } + else + context = (struct timevar_stack_def *) + xmalloc (sizeof (struct timevar_stack_def)); + + /* Fill it in and put it on the stack. */ + context->timevar = tv; + context->next = stack; + stack = context; +} + +/* Pop the topmost timing variable element off the timing stack. The + popped variable must be TIMEVAR. Elapsed time since the that + element was pushed on, or since it was last exposed on top of the + stack when the element above it was popped off, is credited to that + timing variable. */ + +void +timevar_pop (timevar) + timevar_id_t timevar; +{ + struct timevar_time_def now; + struct timevar_stack_def *popped = stack; + + if (!TIMEVAR_ENABLE) + return; + + if (&timevars[timevar] != stack->timevar) + abort (); + + /* What time is it? */ + get_time (&now); + + /* Attribute the elapsed time to the element we're popping. */ + timevar_accumulate (&popped->timevar->elapsed, &start_time, &now); + + /* Reset the start time; from now on, time is attributed to the + element just exposed on the stack. */ + start_time = now; + + /* Take the item off the stack. */ + stack = stack->next; + + /* Don't delete the stack element; instead, add it to the list of + unused elements for later use. */ + popped->next = unused_stack_instances; + unused_stack_instances = popped; +} + +/* Start timing TIMEVAR independently of the timing stack. Elapsed + time until timevar_stop is called for the same timing variable is + attributed to TIMEVAR. */ + +void +timevar_start (timevar) + timevar_id_t timevar; +{ + struct timevar_def *tv = &timevars[timevar]; + + if (!TIMEVAR_ENABLE) + return; + + /* Mark this timing variable as used. */ + tv->used = 1; + + /* Don't allow the same timing variable to be started more than + once. */ + if (tv->standalone) + abort (); + tv->standalone = 1; + + get_time (&tv->start_time); +} + +/* Stop timing TIMEVAR. Time elapsed since timevar_start was called + is attributed to it. */ + +void +timevar_stop (timevar) + timevar_id_t timevar; +{ + struct timevar_def *tv = &timevars[timevar]; + struct timevar_time_def now; + + if (!TIMEVAR_ENABLE) + return; + + /* TIMEVAR must have been started via timevar_start. */ + if (!tv->standalone) + abort (); + + get_time (&now); + timevar_accumulate (&tv->elapsed, &tv->start_time, &now); +} + +/* Fill the elapsed time for TIMEVAR into ELAPSED. Returns + update-to-date information even if TIMEVAR is currently running. */ + +void +timevar_get (timevar, elapsed) + timevar_id_t timevar; + struct timevar_time_def *elapsed; +{ + struct timevar_def *tv = &timevars[timevar]; + struct timevar_time_def now; + + *elapsed = tv->elapsed; + + /* Is TIMEVAR currently running as a standalone timer? */ + if (tv->standalone) + { + get_time (&now); + timevar_accumulate (elapsed, &tv->start_time, &now); + } + /* Or is TIMEVAR at the top of the timer stack? */ + else if (stack->timevar == tv) + { + get_time (&now); + timevar_accumulate (elapsed, &start_time, &now); + } +} + +/* Summarize timing variables to FP. The timing variable TV_TOTAL has + a special meaning -- it's considered to be the total elapsed time, + for normalizing the others, and is displayed last. */ + +void +timevar_print (fp) + FILE *fp; +{ + /* Only print stuff if we have some sort of time information. */ +#if defined HAVE_USER_TIME || defined HAVE_SYS_TIME || defined HAVE_WALL_TIME + unsigned int /* timevar_id_t */ id; + struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed; + struct timevar_time_def now; + + if (!TIMEVAR_ENABLE) + return; + + /* Update timing information in case we're calling this from GDB. */ + + if (fp == 0) + fp = stderr; + + /* What time is it? */ + get_time (&now); + + /* If the stack isn't empty, attribute the current elapsed time to + the old topmost element. */ + if (stack) + timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); + + /* Reset the start time; from now on, time is attributed to + TIMEVAR. */ + start_time = now; + + fputs (_("\nExecution times (seconds)\n"), fp); + for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id) + { + struct timevar_def *tv = &timevars[(timevar_id_t) id]; + const float tiny = 5e-3; + + /* Don't print the total execution time here; that goes at the + end. */ + if ((timevar_id_t) id == TV_TOTAL) + continue; + + /* Don't print timing variables that were never used. */ + if (!tv->used) + continue; + + /* Don't print timing variables if we're going to get a row of + zeroes. */ + if (tv->elapsed.user < tiny + && tv->elapsed.sys < tiny + && tv->elapsed.wall < tiny) + continue; + + /* The timing variable name. */ + fprintf (fp, " %-22s:", tv->name); + +#ifdef HAVE_USER_TIME + /* Print user-mode time for this process. */ + fprintf (fp, "%7.2f (%2.0f%%) usr", + tv->elapsed.user, + (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100); +#endif /* HAVE_USER_TIME */ + +#ifdef HAVE_SYS_TIME + /* Print system-mode time for this process. */ + fprintf (fp, "%7.2f (%2.0f%%) sys", + tv->elapsed.sys, + (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100); +#endif /* HAVE_SYS_TIME */ + +#ifdef HAVE_WALL_TIME + /* Print wall clock time elapsed. */ + fprintf (fp, "%7.2f (%2.0f%%) wall", + tv->elapsed.wall, + (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100); +#endif /* HAVE_WALL_TIME */ + + putc ('\n', fp); + } + + /* Print total time. */ + fputs (_(" TOTAL :"), fp); +#ifdef HAVE_USER_TIME + fprintf (fp, "%7.2f ", total->user); +#endif +#ifdef HAVE_SYS_TIME + fprintf (fp, "%7.2f ", total->sys); +#endif +#ifdef HAVE_WALL_TIME + fprintf (fp, "%7.2f\n", total->wall); +#endif + +#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) + || defined (HAVE_WALL_TIME) */ +} + +/* Returns time (user + system) used so far by the compiler process, + in microseconds. */ + +long +get_run_time () +{ + struct timevar_time_def total_elapsed; + timevar_get (TV_TOTAL, &total_elapsed); + return total_elapsed.user + total_elapsed.sys; +} + +/* Prints a message to stderr stating that time elapsed in STR is + TOTAL (given in microseconds). */ + +void +print_time (str, total) + const char *str; + long total; +{ + long all_time = get_run_time (); + fprintf (stderr, + _("time in %s: %ld.%06ld (%ld%%)\n"), + str, total / 1000000, total % 1000000, + all_time == 0 ? 0 + : (long) (((100.0 * (double) total) / (double) all_time) + .5)); +} diff --git a/lib/timevar.def b/lib/timevar.def new file mode 100644 index 00000000..04ac392b --- /dev/null +++ b/lib/timevar.def @@ -0,0 +1,56 @@ +/* This file contains the definitions for timing variables used to -*- C -*- + measure run-time performance of the compiler. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Akim Demaille <akim@freefriends.org>. + + This file is part of Bison, the GNU Compiler Compiler. + + Bison is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bison is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bison; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* This file contains timing variable definitions, used by timevar.h + and timevar.c. + + Syntax: + + DEFTIMEVAR (id, name) + + where ID is the enumeral value used to identify the timing + variable, and NAME is a character string describing its purpose. */ + +/* The total execution time. */ +DEFTIMEVAR (TV_TOTAL , "total time") + +/* Time spent in the reader. */ +DEFTIMEVAR (TV_READER , "reader") +DEFTIMEVAR (TV_SCANNING , "scanner") +DEFTIMEVAR (TV_PARSING , "parser") + +/* Time spent handling the grammar. */ +DEFTIMEVAR (TV_REDUCE , "reducing the grammar") +DEFTIMEVAR (TV_SETS , "computing the sets") +DEFTIMEVAR (TV_LR0 , "LR(0)") +DEFTIMEVAR (TV_LALR , "LALR(1)") +DEFTIMEVAR (TV_CONFLICTS , "conflicts") + +/* Time spent outputing results. */ +DEFTIMEVAR (TV_REPORT , "outputing report") +DEFTIMEVAR (TV_GRAPH , "outputing graph") +DEFTIMEVAR (TV_ACTIONS , "parser action tables") +DEFTIMEVAR (TV_PARSER , "outputing parser") +DEFTIMEVAR (TV_M4 , "running m4") + +/* Time spent by freeing the memory :). */ +DEFTIMEVAR (TV_FREE , "freeing") diff --git a/lib/timevar.h b/lib/timevar.h new file mode 100644 index 00000000..bbeb4021 --- /dev/null +++ b/lib/timevar.h @@ -0,0 +1,90 @@ +/* Timing variables for measuring compiler performance. + Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc. + Contributed by Alex Samuel <samuel@codesourcery.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef GCC_TIMEVAR_H +#define GCC_TIMEVAR_H + +/* Timing variables are used to measure elapsed time in various + portions of the compiler. Each measures elapsed user, system, and + wall-clock time, as appropriate to and supported by the host + system. + + Timing variables are defined using the DEFTIMEVAR macro in + timevar.def. Each has an enumeral identifier, used when referring + to the timing variable in code, and a character string name. + + Timing variables can be used in two ways: + + - On the timing stack, using timevar_push and timevar_pop. + Timing variables may be pushed onto the stack; elapsed time is + attributed to the topmost timing variable on the stack. When + another variable is pushed on, the previous topmost variable is + `paused' until the pushed variable is popped back off. + + - As a standalone timer, using timevar_start and timevar_stop. + All time elapsed between the two calls is attributed to the + variable. +*/ + +/* This structure stores the various varieties of time that can be + measured. Times are stored in seconds. The time may be an + absolute time or a time difference; in the former case, the time + base is undefined, except that the difference between two times + produces a valid time difference. */ + +struct timevar_time_def +{ + /* User time in this process. */ + float user; + + /* System time (if applicable for this host platform) in this + process. */ + float sys; + + /* Wall clock time. */ + float wall; +}; + +/* An enumeration of timing variable identifiers. Constructed from + the contents of timevar.def. */ + +#define DEFTIMEVAR(identifier__, name__) \ + identifier__, +typedef enum +{ +#include "timevar.def" + TIMEVAR_LAST +} +timevar_id_t; +#undef DEFTIMEVAR + +extern void init_timevar (void); +extern void timevar_push (timevar_id_t); +extern void timevar_pop (timevar_id_t); +extern void timevar_start (timevar_id_t); +extern void timevar_stop (timevar_id_t); +extern void timevar_get (timevar_id_t, struct timevar_time_def *); +extern void timevar_print (FILE *); + +/* Provided for backward compatibility. */ +extern long get_run_time (void); +extern void print_time (const char *, long); + +extern int timevar_report; + +#endif /* ! GCC_TIMEVAR_H */ diff --git a/lib/unistd--.h b/lib/unistd--.h new file mode 100644 index 00000000..1fe6ce8b --- /dev/null +++ b/lib/unistd--.h @@ -0,0 +1,28 @@ +/* Like unistd.h, but redefine some names to avoid glitches. + + Copyright (C) 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +#include <unistd.h> +#include "unistd-safer.h" + +#undef dup +#define dup dup_safer + +#undef pipe +#define pipe pipe_safer diff --git a/lib/unistd-safer.h b/lib/unistd-safer.h new file mode 100644 index 00000000..f95999d3 --- /dev/null +++ b/lib/unistd-safer.h @@ -0,0 +1,23 @@ +/* Invoke unistd-like functions, but avoid some glitches. + + Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert. */ + +int dup_safer (int); +int fd_safer (int); +int pipe_safer (int[2]); diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h new file mode 100644 index 00000000..d0093036 --- /dev/null +++ b/lib/unlocked-io.h @@ -0,0 +1,137 @@ +/* Prefer faster, non-thread-safe stdio functions if available. + + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Jim Meyering. */ + +#ifndef UNLOCKED_IO_H +# define UNLOCKED_IO_H 1 + +/* These are wrappers for functions/macros from the GNU C library, and + from other C libraries supporting POSIX's optional thread-safe functions. + + The standard I/O functions are thread-safe. These *_unlocked ones are + more efficient but not thread-safe. That they're not thread-safe is + fine since all of the applications in this package are single threaded. + + Also, some code that is shared with the GNU C library may invoke + the *_unlocked functions directly. On hosts that lack those + functions, invoke the non-thread-safe versions instead. */ + +# include <stdio.h> + +# if HAVE_DECL_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(x) clearerr_unlocked (x) +# else +# define clearerr_unlocked(x) clearerr (x) +# endif + +# if HAVE_DECL_FEOF_UNLOCKED +# undef feof +# define feof(x) feof_unlocked (x) +# else +# define feof_unlocked(x) feof (x) +# endif + +# if HAVE_DECL_FERROR_UNLOCKED +# undef ferror +# define ferror(x) ferror_unlocked (x) +# else +# define ferror_unlocked(x) ferror (x) +# endif + +# if HAVE_DECL_FFLUSH_UNLOCKED +# undef fflush +# define fflush(x) fflush_unlocked (x) +# else +# define fflush_unlocked(x) fflush (x) +# endif + +# if HAVE_DECL_FGETS_UNLOCKED +# undef fgets +# define fgets(x,y,z) fgets_unlocked (x,y,z) +# else +# define fgets_unlocked(x,y,z) fgets (x,y,z) +# endif + +# if HAVE_DECL_FPUTC_UNLOCKED +# undef fputc +# define fputc(x,y) fputc_unlocked (x,y) +# else +# define fputc_unlocked(x,y) fputc (x,y) +# endif + +# if HAVE_DECL_FPUTS_UNLOCKED +# undef fputs +# define fputs(x,y) fputs_unlocked (x,y) +# else +# define fputs_unlocked(x,y) fputs (x,y) +# endif + +# if HAVE_DECL_FREAD_UNLOCKED +# undef fread +# define fread(w,x,y,z) fread_unlocked (w,x,y,z) +# else +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +# endif + +# if HAVE_DECL_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) +# else +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +# endif + +# if HAVE_DECL_GETC_UNLOCKED +# undef getc +# define getc(x) getc_unlocked (x) +# else +# define getc_unlocked(x) getc (x) +# endif + +# if HAVE_DECL_GETCHAR_UNLOCKED +# undef getchar +# define getchar() getchar_unlocked () +# else +# define getchar_unlocked() getchar () +# endif + +# if HAVE_DECL_PUTC_UNLOCKED +# undef putc +# define putc(x,y) putc_unlocked (x,y) +# else +# define putc_unlocked(x,y) putc (x,y) +# endif + +# if HAVE_DECL_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(x) putchar_unlocked (x) +# else +# define putchar_unlocked(x) putchar (x) +# endif + +# undef flockfile +# define flockfile(x) ((void) 0) + +# undef ftrylockfile +# define ftrylockfile(x) 0 + +# undef funlockfile +# define funlockfile(x) ((void) 0) + +#endif /* UNLOCKED_IO_H */ diff --git a/lib/vbitset.c b/lib/vbitset.c new file mode 100644 index 00000000..d0fe30f6 --- /dev/null +++ b/lib/vbitset.c @@ -0,0 +1,1140 @@ +/* Variable array bitsets. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "vbitset.h" +#include <stdlib.h> +#include <string.h> + +/* This file implements variable size bitsets stored as a variable + length array of words. Any unused bits in the last word must be + zero. + + Note that binary or ternary operations assume that each bitset operand + has the same size. +*/ + +static void vbitset_unused_clear (bitset); + +static void vbitset_set (bitset, bitset_bindex); +static void vbitset_reset (bitset, bitset_bindex); +static bool vbitset_test (bitset, bitset_bindex); +static bitset_bindex vbitset_list (bitset, bitset_bindex *, + bitset_bindex, bitset_bindex *); +static bitset_bindex vbitset_list_reverse (bitset, bitset_bindex *, + bitset_bindex, bitset_bindex *); + +#define VBITSET_N_WORDS(N) (((N) + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) +#define VBITSET_WORDS(X) ((X)->b.cdata) +#define VBITSET_SIZE(X) ((X)->b.csize) +#define VBITSET_ASIZE(X) ((X)->v.size) + +#undef min +#undef max +#define min(a, b) ((a) > (b) ? (b) : (a)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +static bitset_bindex +vbitset_resize (bitset src, bitset_bindex n_bits) +{ + bitset_windex oldsize; + bitset_windex newsize; + + if (n_bits == BITSET_NBITS_ (src)) + return n_bits; + + oldsize = VBITSET_SIZE (src); + newsize = VBITSET_N_WORDS (n_bits); + + if (oldsize < newsize) + { + bitset_windex size; + + /* The bitset needs to grow. If we already have enough memory + allocated, then just zero what we need. */ + if (newsize > VBITSET_ASIZE (src)) + { + /* We need to allocate more memory. When oldsize is + non-zero this means that we are changing the size, so + grow the bitset 25% larger than requested to reduce + number of reallocations. */ + + if (oldsize == 0) + size = newsize; + else + size = newsize + newsize / 4; + + VBITSET_WORDS (src) + = realloc (VBITSET_WORDS (src), size * sizeof (bitset_word)); + VBITSET_ASIZE (src) = size; + } + + memset (VBITSET_WORDS (src) + oldsize, 0, + (newsize - oldsize) * sizeof (bitset_word)); + VBITSET_SIZE (src) = newsize; + } + else + { + /* The bitset needs to shrink. There's no point deallocating + the memory unless it is shrinking by a reasonable amount. */ + if ((oldsize - newsize) >= oldsize / 2) + { + VBITSET_WORDS (src) + = realloc (VBITSET_WORDS (src), newsize * sizeof (bitset_word)); + VBITSET_ASIZE (src) = newsize; + } + + /* Need to prune any excess bits. FIXME. */ + + VBITSET_SIZE (src) = newsize; + } + + BITSET_NBITS_ (src) = n_bits; + return n_bits; +} + + +/* Set bit BITNO in bitset DST. */ +static void +vbitset_set (dst, bitno) + bitset dst; + bitset_bindex bitno; +{ + bitset_windex windex = bitno / BITSET_WORD_BITS; + + /* Perhaps we should abort. The user should explicitly call + bitset_resize since this will not catch the case when we set a + bit larger than the current size but smaller than the allocated + size. */ + vbitset_resize (dst, bitno); + + dst->b.cdata[windex - dst->b.cindex] |= + (bitset_word) 1 << (bitno % BITSET_WORD_BITS); +} + + +/* Reset bit BITNO in bitset DST. */ +static void +vbitset_reset (dst, bitno) + bitset dst ATTRIBUTE_UNUSED; + bitset_bindex bitno ATTRIBUTE_UNUSED; +{ + /* We must be accessing outside the cache so the bit is + zero anyway. */ +} + + +/* Test bit BITNO in bitset SRC. */ +static bool +vbitset_test (src, bitno) + bitset src ATTRIBUTE_UNUSED; + bitset_bindex bitno ATTRIBUTE_UNUSED; +{ + /* We must be accessing outside the cache so the bit is + zero anyway. */ + return 0; +} + + +/* Find list of up to NUM bits set in BSET in reverse order, starting + from and including NEXT and store in array LIST. Return with + actual number of bits found and with *NEXT indicating where search + stopped. */ +static bitset_bindex +vbitset_list_reverse (src, list, num, next) + bitset src; + bitset_bindex *list; + bitset_bindex num; + bitset_bindex *next; +{ + bitset_bindex bitno; + bitset_bindex rbitno; + bitset_bindex count; + bitset_windex windex; + unsigned int bitcnt; + bitset_bindex bitoff; + bitset_word *srcp = VBITSET_WORDS (src); + bitset_bindex n_bits = BITSET_SIZE_ (src); + + rbitno = *next; + + /* If num is 1, we could speed things up with a binary search + of the word of interest. */ + + if (rbitno >= n_bits) + return 0; + + count = 0; + + bitno = n_bits - (rbitno + 1); + + windex = bitno / BITSET_WORD_BITS; + bitcnt = bitno % BITSET_WORD_BITS; + bitoff = windex * BITSET_WORD_BITS; + + do + { + bitset_word word; + + word = srcp[windex] << (BITSET_WORD_BITS - 1 - bitcnt); + for (; word; bitcnt--) + { + if (word & BITSET_MSB) + { + list[count++] = bitoff + bitcnt; + if (count >= num) + { + *next = n_bits - (bitoff + bitcnt); + return count; + } + } + word <<= 1; + } + bitoff -= BITSET_WORD_BITS; + bitcnt = BITSET_WORD_BITS - 1; + } + while (windex--); + + *next = n_bits - (bitoff + 1); + return count; +} + + +/* Find list of up to NUM bits set in BSET starting from and including + *NEXT and store in array LIST. Return with actual number of bits + found and with *NEXT indicating where search stopped. */ +static bitset_bindex +vbitset_list (src, list, num, next) + bitset src; + bitset_bindex *list; + bitset_bindex num; + bitset_bindex *next; +{ + bitset_bindex bitno; + bitset_bindex count; + bitset_windex windex; + bitset_bindex bitoff; + bitset_windex size = VBITSET_SIZE (src); + bitset_word *srcp = VBITSET_WORDS (src); + bitset_word word; + + bitno = *next; + + count = 0; + if (!bitno) + { + /* Many bitsets are zero, so make this common case fast. */ + for (windex = 0; windex < size && !srcp[windex]; windex++) + continue; + if (windex >= size) + return 0; + + /* If num is 1, we could speed things up with a binary search + of the current word. */ + + bitoff = windex * BITSET_WORD_BITS; + } + else + { + if (bitno >= BITSET_SIZE_ (src)) + return 0; + + windex = bitno / BITSET_WORD_BITS; + bitno = bitno % BITSET_WORD_BITS; + + if (bitno) + { + /* Handle the case where we start within a word. + Most often, this is executed with large bitsets + with many set bits where we filled the array + on the previous call to this function. */ + + bitoff = windex * BITSET_WORD_BITS; + word = srcp[windex] >> bitno; + for (bitno = bitoff + bitno; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + windex++; + } + bitoff = windex * BITSET_WORD_BITS; + } + + for (; windex < size; windex++, bitoff += BITSET_WORD_BITS) + { + if (!(word = srcp[windex])) + continue; + + if ((count + BITSET_WORD_BITS) < num) + { + for (bitno = bitoff; word; bitno++) + { + if (word & 1) + list[count++] = bitno; + word >>= 1; + } + } + else + { + for (bitno = bitoff; word; bitno++) + { + if (word & 1) + { + list[count++] = bitno; + if (count >= num) + { + *next = bitno + 1; + return count; + } + } + word >>= 1; + } + } + } + + *next = bitoff; + return count; +} + + +/* Ensure that any unused bits within the last word are clear. */ +static inline void +vbitset_unused_clear (dst) + bitset dst; +{ + unsigned int last_bit; + + last_bit = BITSET_SIZE_ (dst) % BITSET_WORD_BITS; + if (last_bit) + VBITSET_WORDS (dst)[VBITSET_SIZE (dst) - 1] &= + ((bitset_word) 1 << last_bit) - 1; +} + + +static void +vbitset_ones (bitset dst) +{ + bitset_word *dstp = VBITSET_WORDS (dst); + unsigned int bytes; + + bytes = sizeof (bitset_word) * VBITSET_SIZE (dst); + + memset (dstp, -1, bytes); + vbitset_unused_clear (dst); +} + + +static void +vbitset_zero (bitset dst) +{ + bitset_word *dstp = VBITSET_WORDS (dst); + unsigned int bytes; + + bytes = sizeof (bitset_word) * VBITSET_SIZE (dst); + + memset (dstp, 0, bytes); +} + + +static bool +vbitset_empty_p (bitset dst) +{ + unsigned int i; + bitset_word *dstp = VBITSET_WORDS (dst); + + for (i = 0; i < VBITSET_SIZE (dst); i++) + if (dstp[i]) + return 0; + + return 1; +} + + +static void +vbitset_copy1 (bitset dst, bitset src) +{ + bitset_word *srcp; + bitset_word *dstp; + bitset_windex ssize; + bitset_windex dsize; + + if (src == dst) + return; + + vbitset_resize (dst, BITSET_SIZE_ (src)); + + srcp = VBITSET_WORDS (src); + dstp = VBITSET_WORDS (dst); + ssize = VBITSET_SIZE (src); + dsize = VBITSET_SIZE (dst); + + memcpy (dstp, srcp, sizeof (bitset_word) * ssize); + + memset (dstp + sizeof (bitset_word) * ssize, 0, + sizeof (bitset_word) * (dsize - ssize)); +} + + +static void +vbitset_not (bitset dst, bitset src) +{ + unsigned int i; + bitset_word *srcp; + bitset_word *dstp; + bitset_windex ssize; + bitset_windex dsize; + + vbitset_resize (dst, BITSET_SIZE_ (src)); + + srcp = VBITSET_WORDS (src); + dstp = VBITSET_WORDS (dst); + ssize = VBITSET_SIZE (src); + dsize = VBITSET_SIZE (dst); + + for (i = 0; i < ssize; i++) + *dstp++ = ~(*srcp++); + + vbitset_unused_clear (dst); + memset (dstp + sizeof (bitset_word) * ssize, 0, + sizeof (bitset_word) * (dsize - ssize)); +} + + +static bool +vbitset_equal_p (bitset dst, bitset src) +{ + unsigned int i; + bitset_word *srcp = VBITSET_WORDS (src); + bitset_word *dstp = VBITSET_WORDS (dst); + bitset_windex ssize = VBITSET_SIZE (src); + bitset_windex dsize = VBITSET_SIZE (dst); + + for (i = 0; i < min (ssize, dsize); i++) + if (*srcp++ != *dstp++) + return 0; + + if (ssize > dsize) + { + for (; i < ssize; i++) + if (*srcp++) + return 0; + } + else + { + for (; i < dsize; i++) + if (*dstp++) + return 0; + } + + return 1; +} + + +static bool +vbitset_subset_p (bitset dst, bitset src) +{ + unsigned int i; + bitset_word *srcp = VBITSET_WORDS (src); + bitset_word *dstp = VBITSET_WORDS (dst); + bitset_windex ssize = VBITSET_SIZE (src); + bitset_windex dsize = VBITSET_SIZE (dst); + + for (i = 0; i < min (ssize, dsize); i++, dstp++, srcp++) + if (*dstp != (*srcp | *dstp)) + return 0; + + if (ssize > dsize) + { + for (; i < ssize; i++) + if (*srcp++) + return 0; + } + + return 1; +} + + +static bool +vbitset_disjoint_p (bitset dst, bitset src) +{ + unsigned int i; + bitset_word *srcp = VBITSET_WORDS (src); + bitset_word *dstp = VBITSET_WORDS (dst); + bitset_windex ssize = VBITSET_SIZE (src); + bitset_windex dsize = VBITSET_SIZE (dst); + + for (i = 0; i < min (ssize, dsize); i++) + if (*srcp++ & *dstp++) + return 0; + + return 1; +} + + +static void +vbitset_and (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++) + *dstp++ = *src1p++ & *src2p++; + + memset (dstp, 0, sizeof (bitset_word) * (dsize - min (ssize1, ssize2))); +} + + +static bool +vbitset_and_cmp (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++, dstp++) + { + bitset_word tmp = *src1p++ & *src2p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + if (ssize2 > ssize1) + { + src1p = src2p; + ssize1 = ssize2; + } + + for (; i < ssize1; i++, dstp++) + { + if (*dstp != 0) + { + changed = 1; + *dstp = 0; + } + } + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); + + return changed; +} + + +static void +vbitset_andn (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++) + *dstp++ = *src1p++ & ~(*src2p++); + + if (ssize2 > ssize1) + { + for (; i < ssize2; i++) + *dstp++ = 0; + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize2)); + } + else + { + for (; i < ssize1; i++) + *dstp++ = *src1p++; + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); + } +} + + +static bool +vbitset_andn_cmp (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++, dstp++) + { + bitset_word tmp = *src1p++ & ~(*src2p++); + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + if (ssize2 > ssize1) + { + for (; i < ssize2; i++, dstp++) + { + if (*dstp != 0) + { + changed = 1; + *dstp = 0; + } + } + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize2)); + } + else + { + for (; i < ssize1; i++, dstp++) + { + bitset_word tmp = *src1p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); + } + + return changed; +} + + +static void +vbitset_or (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++) + *dstp++ = *src1p++ | *src2p++; + + if (ssize2 > ssize1) + { + src1p = src2p; + ssize1 = ssize2; + } + + for (; i < ssize1; i++) + *dstp++ = *src1p++; + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); +} + + +static bool +vbitset_or_cmp (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++, dstp++) + { + bitset_word tmp = *src1p++ | *src2p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + if (ssize2 > ssize1) + { + src1p = src2p; + ssize1 = ssize2; + } + + for (; i < ssize1; i++, dstp++) + { + bitset_word tmp = *src1p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); + + return changed; +} + + +static void +vbitset_xor (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++) + *dstp++ = *src1p++ ^ *src2p++; + + if (ssize2 > ssize1) + { + src1p = src2p; + ssize1 = ssize2; + } + + for (; i < ssize1; i++) + *dstp++ = *src1p++; + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); +} + + +static bool +vbitset_xor_cmp (bitset dst, bitset src1, bitset src2) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *dstp; + bitset_windex ssize1; + bitset_windex ssize2; + bitset_windex dsize; + + vbitset_resize (dst, max (BITSET_SIZE_ (src1), BITSET_SIZE_ (src2))); + + dsize = VBITSET_SIZE (dst); + ssize1 = VBITSET_SIZE (src1); + ssize2 = VBITSET_SIZE (src2); + dstp = VBITSET_WORDS (dst); + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + + for (i = 0; i < min (ssize1, ssize2); i++, dstp++) + { + bitset_word tmp = *src1p++ ^ *src2p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + if (ssize2 > ssize1) + { + src1p = src2p; + ssize1 = ssize2; + } + + for (; i < ssize1; i++, dstp++) + { + bitset_word tmp = *src1p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + + memset (dstp, 0, sizeof (bitset_word) * (dsize - ssize1)); + + return changed; +} + + +/* FIXME, these operations need fixing for different size + bitsets. */ + +static void +vbitset_and_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + { + bitset_and_or_ (dst, src1, src2, src3); + return; + } + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ & *src2p++) | *src3p++; +} + + +static bool +vbitset_and_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + return bitset_and_or_cmp_ (dst, src1, src2, src3); + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ & *src2p++) | *src3p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + return changed; +} + + +static void +vbitset_andn_or (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + { + bitset_andn_or_ (dst, src1, src2, src3); + return; + } + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ & ~(*src2p++)) | *src3p++; +} + + +static bool +vbitset_andn_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + return bitset_andn_or_cmp_ (dst, src1, src2, src3); + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ & ~(*src2p++)) | *src3p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + return changed; +} + + +static void +vbitset_or_and (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + { + bitset_or_and_ (dst, src1, src2, src3); + return; + } + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++) + *dstp++ = (*src1p++ | *src2p++) & *src3p++; +} + + +static bool +vbitset_or_and_cmp (bitset dst, bitset src1, bitset src2, bitset src3) +{ + unsigned int i; + int changed = 0; + bitset_word *src1p; + bitset_word *src2p; + bitset_word *src3p; + bitset_word *dstp; + bitset_windex size; + + if (BITSET_NBITS_ (src1) != BITSET_NBITS_ (src2) + || BITSET_NBITS_ (src1) != BITSET_NBITS_ (src3)) + return bitset_or_and_cmp_ (dst, src1, src2, src3); + + vbitset_resize (dst, BITSET_NBITS_ (src1)); + + src1p = VBITSET_WORDS (src1); + src2p = VBITSET_WORDS (src2); + src3p = VBITSET_WORDS (src3); + dstp = VBITSET_WORDS (dst); + size = VBITSET_SIZE (dst); + + for (i = 0; i < size; i++, dstp++) + { + bitset_word tmp = (*src1p++ | *src2p++) & *src3p++; + + if (*dstp != tmp) + { + changed = 1; + *dstp = tmp; + } + } + return changed; +} + + +static void +vbitset_copy (bitset dst, bitset src) +{ + if (BITSET_COMPATIBLE_ (dst, src)) + vbitset_copy1 (dst, src); + else + bitset_copy_ (dst, src); +} + + +/* Vector of operations for multiple word bitsets. */ +struct bitset_vtable vbitset_vtable = { + vbitset_set, + vbitset_reset, + bitset_toggle_, + vbitset_test, + vbitset_resize, + bitset_size_, + bitset_count_, + vbitset_empty_p, + vbitset_ones, + vbitset_zero, + vbitset_copy, + vbitset_disjoint_p, + vbitset_equal_p, + vbitset_not, + vbitset_subset_p, + vbitset_and, + vbitset_and_cmp, + vbitset_andn, + vbitset_andn_cmp, + vbitset_or, + vbitset_or_cmp, + vbitset_xor, + vbitset_xor_cmp, + vbitset_and_or, + vbitset_and_or_cmp, + vbitset_andn_or, + vbitset_andn_or_cmp, + vbitset_or_and, + vbitset_or_and_cmp, + vbitset_list, + vbitset_list_reverse, + NULL, + BITSET_VARRAY +}; + + +size_t +vbitset_bytes (n_bits) + bitset_bindex n_bits ATTRIBUTE_UNUSED; +{ + return sizeof (struct vbitset_struct); +} + + +bitset +vbitset_init (bset, n_bits) + bitset bset; + bitset_bindex n_bits; +{ + bset->b.vtable = &vbitset_vtable; + + bset->b.cindex = 0; + + VBITSET_SIZE (bset) = 0; + vbitset_resize (bset, n_bits); + return bset; +} diff --git a/lib/vbitset.h b/lib/vbitset.h new file mode 100644 index 00000000..bab011c4 --- /dev/null +++ b/lib/vbitset.h @@ -0,0 +1,28 @@ +/* Functions to support vbitsets. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _VBITSET_H +#define _VBITSET_H + +#include "bitset.h" + +extern size_t vbitset_bytes (bitset_bindex); + +extern bitset vbitset_init (bitset, bitset_bindex); + +#endif diff --git a/lib/verify.h b/lib/verify.h new file mode 100644 index 00000000..d603b173 --- /dev/null +++ b/lib/verify.h @@ -0,0 +1,141 @@ +/* Compile-time assert-like macros. + + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */ + +#ifndef VERIFY_H +# define VERIFY_H 1 + +/* Each of these macros verifies that its argument R is nonzero. To + be portable, R should be an integer constant expression. Unlike + assert (R), there is no run-time overhead. + + There are two macros, since no single macro can be used in all + contexts in C. verify_true (R) is for scalar contexts, including + integer constant expression contexts. verify (R) is for declaration + contexts, e.g., the top level. + + Symbols ending in "__" are private to this header. + + The code below uses several ideas. + + * The first step is ((R) ? 1 : -1). Given an expression R, of + integral or boolean or floating-point type, this yields an + expression of integral type, whose value is later verified to be + constant and nonnegative. + + * Next this expression W is wrapped in a type + struct verify_type__ { unsigned int verify_error_if_negative_size__: W; }. + If W is negative, this yields a compile-time error. No compiler can + deal with a bit-field of negative size. + + One might think that an array size check would have the same + effect, that is, that the type struct { unsigned int dummy[W]; } + would work as well. However, inside a function, some compilers + (such as C++ compilers and GNU C) allow local parameters and + variables inside array size expressions. With these compilers, + an array size check would not properly diagnose this misuse of + the verify macro: + + void function (int n) { verify (n < 0); } + + * For the verify macro, the struct verify_type__ will need to + somehow be embedded into a declaration. To be portable, this + declaration must declare an object, a constant, a function, or a + typedef name. If the declared entity uses the type directly, + such as in + + struct dummy {...}; + typedef struct {...} dummy; + extern struct {...} *dummy; + extern void dummy (struct {...} *); + extern struct {...} *dummy (void); + + two uses of the verify macro would yield colliding declarations + if the entity names are not disambiguated. A workaround is to + attach the current line number to the entity name: + + #define GL_CONCAT0(x, y) x##y + #define GL_CONCAT(x, y) GL_CONCAT0 (x, y) + extern struct {...} * GL_CONCAT(dummy,__LINE__); + + But this has the problem that two invocations of verify from + within the same macro would collide, since the __LINE__ value + would be the same for both invocations. + + A solution is to use the sizeof operator. It yields a number, + getting rid of the identity of the type. Declarations like + + extern int dummy [sizeof (struct {...})]; + extern void dummy (int [sizeof (struct {...})]); + extern int (*dummy (void)) [sizeof (struct {...})]; + + can be repeated. + + * Should the implementation use a named struct or an unnamed struct? + Which of the following alternatives can be used? + + extern int dummy [sizeof (struct {...})]; + extern int dummy [sizeof (struct verify_type__ {...})]; + extern void dummy (int [sizeof (struct {...})]); + extern void dummy (int [sizeof (struct verify_type__ {...})]); + extern int (*dummy (void)) [sizeof (struct {...})]; + extern int (*dummy (void)) [sizeof (struct verify_type__ {...})]; + + In the second and sixth case, the struct type is exported to the + outer scope; two such declarations therefore collide. GCC warns + about the first, third, and fourth cases. So the only remaining + possibility is the fifth case: + + extern int (*dummy (void)) [sizeof (struct {...})]; + + * This implementation exploits the fact that GCC does not warn about + the last declaration mentioned above. If a future version of GCC + introduces a warning for this, the problem could be worked around + by using code specialized to GCC, e.g.,: + + #if 4 <= __GNUC__ + # define verify(R) \ + extern int (* verify_function__ (void)) \ + [__builtin_constant_p (R) && (R) ? 1 : -1] + #endif + + * In C++, any struct definition inside sizeof is invalid. + Use a template type to work around the problem. */ + + +/* Verify requirement R at compile-time, as an integer constant expression. + Return 1. */ + +# ifdef __cplusplus +template <int w> + struct verify_type__ { unsigned int verify_error_if_negative_size__: w; }; +# define verify_true(R) \ + (!!sizeof (verify_type__<(R) ? 1 : -1>)) +# else +# define verify_true(R) \ + (!!sizeof \ + (struct { unsigned int verify_error_if_negative_size__: (R) ? 1 : -1; })) +# endif + +/* Verify requirement R at compile-time, as a declaration without a + trailing ';'. */ + +# define verify(R) extern int (* verify_function__ (void)) [verify_true (R)] + +#endif diff --git a/lib/xalloc-die.c b/lib/xalloc-die.c new file mode 100644 index 00000000..9b4a76c6 --- /dev/null +++ b/lib/xalloc-die.c @@ -0,0 +1,44 @@ +/* Report a memory allocation failure and exit. + + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2006 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "xalloc.h" + +#include <stdlib.h> + +#include "error.h" +#include "exitfail.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +void +xalloc_die (void) +{ + error (exit_failure, 0, "%s", _("memory exhausted")); + + /* The `noreturn' cannot be given to error, since it may return if + its first argument is 0. To help compilers understand the + xalloc_die does not return, call abort. Also, the abort is a + safety feature if exit_failure is 0 (which shouldn't happen). */ + abort (); +} diff --git a/lib/xalloc.h b/lib/xalloc.h new file mode 100644 index 00000000..f80977e3 --- /dev/null +++ b/lib/xalloc.h @@ -0,0 +1,79 @@ +/* xalloc.h -- malloc with out-of-memory checking + + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef XALLOC_H_ +# define XALLOC_H_ + +# include <stddef.h> + + +# ifdef __cplusplus +extern "C" { +# endif + + +# ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +# endif + +# ifndef ATTRIBUTE_NORETURN +# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +# endif + +/* This function is always triggered when memory is exhausted. + It must be defined by the application, either explicitly + or by using gnulib's xalloc-die module. This is the + function to call when one wants the program to die because of a + memory allocation failure. */ +extern void xalloc_die (void) ATTRIBUTE_NORETURN; + +void *xmalloc (size_t s); +void *xnmalloc (size_t n, size_t s); +void *xzalloc (size_t s); +void *xcalloc (size_t n, size_t s); +void *xrealloc (void *p, size_t s); +void *xnrealloc (void *p, size_t n, size_t s); +void *x2realloc (void *p, size_t *pn); +void *x2nrealloc (void *p, size_t *pn, size_t s); +void *xmemdup (void const *p, size_t s); +char *xstrdup (char const *str); + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not an inline function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +# ifdef __cplusplus +} +# endif + + +#endif /* !XALLOC_H_ */ diff --git a/lib/xmalloc.c b/lib/xmalloc.c new file mode 100644 index 00000000..687633c2 --- /dev/null +++ b/lib/xmalloc.c @@ -0,0 +1,241 @@ +/* xmalloc.c -- malloc with out of memory checking + + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "xalloc.h" + +#include <stdlib.h> +#include <string.h> + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* 1 if calloc is known to be compatible with GNU calloc. This + matters if we are not also using the calloc module, which defines + HAVE_CALLOC and supports the GNU API even on non-GNU platforms. */ +#if defined HAVE_CALLOC || defined __GLIBC__ +enum { HAVE_GNU_CALLOC = 1 }; +#else +enum { HAVE_GNU_CALLOC = 0 }; +#endif + +/* Allocate an array of N objects, each with S bytes of memory, + dynamically, with error checking. S must be nonzero. */ + +static inline void * +xnmalloc_inline (size_t n, size_t s) +{ + void *p; + if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0)) + xalloc_die (); + return p; +} + +void * +xnmalloc (size_t n, size_t s) +{ + return xnmalloc_inline (n, s); +} + +/* Allocate N bytes of memory dynamically, with error checking. */ + +void * +xmalloc (size_t n) +{ + return xnmalloc_inline (n, 1); +} + +/* Change the size of an allocated block of memory P to an array of N + objects each of S bytes, with error checking. S must be nonzero. */ + +static inline void * +xnrealloc_inline (void *p, size_t n, size_t s) +{ + if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0)) + xalloc_die (); + return p; +} + +void * +xnrealloc (void *p, size_t n, size_t s) +{ + return xnrealloc_inline (p, n, s); +} + +/* Change the size of an allocated block of memory P to N bytes, + with error checking. */ + +void * +xrealloc (void *p, size_t n) +{ + return xnrealloc_inline (p, n, 1); +} + + +/* If P is null, allocate a block of at least *PN such objects; + otherwise, reallocate P so that it contains more than *PN objects + each of S bytes. *PN must be nonzero unless P is null, and S must + be nonzero. Set *PN to the new number of objects, and return the + pointer to the new block. *PN is never set to zero, and the + returned pointer is never null. + + Repeated reallocations are guaranteed to make progress, either by + allocating an initial block with a nonzero size, or by allocating a + larger block. + + In the following implementation, nonzero sizes are doubled so that + repeated reallocations have O(N log N) overall cost rather than + O(N**2) cost, but the specification for this function does not + guarantee that sizes are doubled. + + Here is an example of use: + + int *p = NULL; + size_t used = 0; + size_t allocated = 0; + + void + append_int (int value) + { + if (used == allocated) + p = x2nrealloc (p, &allocated, sizeof *p); + p[used++] = value; + } + + This causes x2nrealloc to allocate a block of some nonzero size the + first time it is called. + + To have finer-grained control over the initial size, set *PN to a + nonzero value before calling this function with P == NULL. For + example: + + int *p = NULL; + size_t used = 0; + size_t allocated = 0; + size_t allocated1 = 1000; + + void + append_int (int value) + { + if (used == allocated) + { + p = x2nrealloc (p, &allocated1, sizeof *p); + allocated = allocated1; + } + p[used++] = value; + } + + */ + +static inline void * +x2nrealloc_inline (void *p, size_t *pn, size_t s) +{ + size_t n = *pn; + + if (! p) + { + if (! n) + { + /* The approximate size to use for initial small allocation + requests, when the invoking code specifies an old size of + zero. 64 bytes is the largest "small" request for the + GNU C library malloc. */ + enum { DEFAULT_MXFAST = 64 }; + + n = DEFAULT_MXFAST / s; + n += !n; + } + } + else + { + if (SIZE_MAX / 2 / s < n) + xalloc_die (); + n *= 2; + } + + *pn = n; + return xrealloc (p, n * s); +} + +void * +x2nrealloc (void *p, size_t *pn, size_t s) +{ + return x2nrealloc_inline (p, pn, s); +} + +/* If P is null, allocate a block of at least *PN bytes; otherwise, + reallocate P so that it contains more than *PN bytes. *PN must be + nonzero unless P is null. Set *PN to the new block's size, and + return the pointer to the new block. *PN is never set to zero, and + the returned pointer is never null. */ + +void * +x2realloc (void *p, size_t *pn) +{ + return x2nrealloc_inline (p, pn, 1); +} + +/* Allocate S bytes of zeroed memory dynamically, with error checking. + There's no need for xnzalloc (N, S), since it would be equivalent + to xcalloc (N, S). */ + +void * +xzalloc (size_t s) +{ + return memset (xmalloc (s), 0, s); +} + +/* Allocate zeroed memory for N elements of S bytes, with error + checking. S must be nonzero. */ + +void * +xcalloc (size_t n, size_t s) +{ + void *p; + /* Test for overflow, since some calloc implementations don't have + proper overflow checks. But omit overflow and size-zero tests if + HAVE_GNU_CALLOC, since GNU calloc catches overflow and never + returns NULL if successful. */ + if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) + || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) + xalloc_die (); + return p; +} + +/* Clone an object P of size S, with error checking. There's no need + for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any + need for an arithmetic overflow check. */ + +void * +xmemdup (void const *p, size_t s) +{ + return memcpy (xmalloc (s), p, s); +} + +/* Clone STRING. */ + +char * +xstrdup (char const *string) +{ + return xmemdup (string, strlen (string) + 1); +} diff --git a/lib/xstrndup.c b/lib/xstrndup.c new file mode 100644 index 00000000..a62d4bd6 --- /dev/null +++ b/lib/xstrndup.c @@ -0,0 +1,39 @@ +/* Duplicate a bounded initial segment of a string, with out-of-memory + checking. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "xstrndup.h" + +#include "strndup.h" +#include "xalloc.h" + +/* Return a newly allocated copy of at most N bytes of STRING. + In other words, return a copy of the initial segment of length N of + STRING. */ +char * +xstrndup (const char *string, size_t n) +{ + char *s = strndup (string, n); + if (! s) + xalloc_die (); + return s; +} diff --git a/lib/xstrndup.h b/lib/xstrndup.h new file mode 100644 index 00000000..88354cfd --- /dev/null +++ b/lib/xstrndup.h @@ -0,0 +1,24 @@ +/* Duplicate a bounded initial segment of a string, with out-of-memory + checking. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <stddef.h> + +/* Return a newly allocated copy of at most N bytes of STRING. + In other words, return a copy of the initial segment of length N of + STRING. */ +extern char *xstrndup (const char *string, size_t n); diff --git a/lib/yyerror.c b/lib/yyerror.c new file mode 100644 index 00000000..b4ce4ba9 --- /dev/null +++ b/lib/yyerror.c @@ -0,0 +1,30 @@ +/* Yacc library error-printing function. + + Copyright (C) 2002 Free Software Foundation, Inc. + + This file is part of Bison, the GNU Compiler Compiler. + + Bison is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bison is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bison; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include <stdio.h> + +int yyerror (char const *); + +int +yyerror (char const *message) +{ + return fprintf (stderr, "%s\n", message); +} |