diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf')
18 files changed, 7275 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.am b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.am new file mode 100644 index 00000000000..f096b1c41bf --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in +AUTOMAKE_OPTIONS = foreign + +noinst_LIBRARIES = liblcdf.a + +liblcdf_a_SOURCES = bezier.cc \ + clp.c \ + error.cc \ + filename.cc \ + globmatch.cc \ + landmark.cc \ + md5.c \ + permstr.cc \ + point.cc \ + slurper.cc \ + straccum.cc \ + string.cc \ + strtonum.c \ + transform.cc \ + vectorv.cc + +if FIXLIBC +liblcdf_a_SOURCES += fixlibc.c +endif FIXLIBC + +liblcdf_a_LIBADD = @TEMPLATE_OBJS@ +CLEANFILES = @TEMPLATE_OBJS@ + +AM_CPPFLAGS = -I$(srcdir)/../include + +EXTRA_DIST = fixlibc.c diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.in b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.in new file mode 100644 index 00000000000..5c19bd59f17 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/Makefile.in @@ -0,0 +1,675 @@ +# Makefile.in generated by automake 1.14 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 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@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +@FIXLIBC_TRUE@am__append_1 = fixlibc.c +subdir = lcdf-typetools-2.99/liblcdf +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/../../build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_cxx_template_objs.m4 \ + $(top_srcdir)/../../m4/kpse-common.m4 \ + $(top_srcdir)/../../m4/kpse-cxx-hack.m4 \ + $(top_srcdir)/../../m4/kpse-kpathsea-flags.m4 \ + $(top_srcdir)/../../m4/kpse-warnings.m4 \ + $(top_srcdir)/../../m4/kpse-win32.m4 \ + $(top_srcdir)/../../m4/libtool.m4 \ + $(top_srcdir)/../../m4/ltoptions.m4 \ + $(top_srcdir)/../../m4/ltsugar.m4 \ + $(top_srcdir)/../../m4/ltversion.m4 \ + $(top_srcdir)/../../m4/lt~obsolete.m4 $(top_srcdir)/version.ac \ + $(top_srcdir)/ac/lcdf-typetools.ac $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +liblcdf_a_AR = $(AR) $(ARFLAGS) +liblcdf_a_DEPENDENCIES = +am__liblcdf_a_SOURCES_DIST = bezier.cc clp.c error.cc filename.cc \ + globmatch.cc landmark.cc md5.c permstr.cc point.cc slurper.cc \ + straccum.cc string.cc strtonum.c transform.cc vectorv.cc \ + fixlibc.c +@FIXLIBC_TRUE@am__objects_1 = fixlibc.$(OBJEXT) +am_liblcdf_a_OBJECTS = bezier.$(OBJEXT) clp.$(OBJEXT) error.$(OBJEXT) \ + filename.$(OBJEXT) globmatch.$(OBJEXT) landmark.$(OBJEXT) \ + md5.$(OBJEXT) permstr.$(OBJEXT) point.$(OBJEXT) \ + slurper.$(OBJEXT) straccum.$(OBJEXT) string.$(OBJEXT) \ + strtonum.$(OBJEXT) transform.$(OBJEXT) vectorv.$(OBJEXT) \ + $(am__objects_1) +liblcdf_a_OBJECTS = $(am_liblcdf_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../../build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(liblcdf_a_SOURCES) +DIST_SOURCES = $(am__liblcdf_a_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXLD = @CXXLD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KPATHSEA_DEPEND = @KPATHSEA_DEPEND@ +KPATHSEA_INCLUDES = @KPATHSEA_INCLUDES@ +KPATHSEA_LIBS = @KPATHSEA_LIBS@ +LCDF_TYPETOOLS_TREE = @LCDF_TYPETOOLS_TREE@ +LCDF_TYPETOOLS_VERSION = @LCDF_TYPETOOLS_VERSION@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SELECTED_SUBDIRS = @SELECTED_SUBDIRS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEMPLATE_OBJS = @TEMPLATE_OBJS@ +VERSION = @VERSION@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +WARNING_CXXFLAGS = @WARNING_CXXFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +encdir = @encdir@ +exec_prefix = @exec_prefix@ +glyphlistdir = @glyphlistdir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = liblcdf.a +liblcdf_a_SOURCES = bezier.cc clp.c error.cc filename.cc globmatch.cc \ + landmark.cc md5.c permstr.cc point.cc slurper.cc straccum.cc \ + string.cc strtonum.c transform.cc vectorv.cc $(am__append_1) +liblcdf_a_LIBADD = @TEMPLATE_OBJS@ +CLEANFILES = @TEMPLATE_OBJS@ +AM_CPPFLAGS = -I$(srcdir)/../include +EXTRA_DIST = fixlibc.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .cc .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lcdf-typetools-2.99/liblcdf/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lcdf-typetools-2.99/liblcdf/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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +liblcdf.a: $(liblcdf_a_OBJECTS) $(liblcdf_a_DEPENDENCIES) $(EXTRA_liblcdf_a_DEPENDENCIES) + $(AM_V_at)-rm -f liblcdf.a + $(AM_V_AR)$(liblcdf_a_AR) liblcdf.a $(liblcdf_a_OBJECTS) $(liblcdf_a_LIBADD) + $(AM_V_at)$(RANLIB) liblcdf.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bezier.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filename.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fixlibc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globmatch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/landmark.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/permstr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/point.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slurper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/straccum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtonum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vectorv.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: 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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# 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/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/bezier.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/bezier.cc new file mode 100644 index 00000000000..95c8d8b9fb0 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/bezier.cc @@ -0,0 +1,376 @@ +// -*- related-file-name: "../include/lcdf/bezier.hh" -*- + +/* bezier.{cc,hh} -- cubic Bezier curves + * + * Copyright (c) 1998-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/bezier.hh> + +// +// bounding box +// + +void +Bezier::make_bb() const throw () +{ + _bb = 0; + for (int i = 1; i < 4; i++) { + if (_p[i].x > bb_right_x()) + _bb = (_bb & ~0x03) | (i << 0); + else if (_p[i].x < bb_left_x()) + _bb = (_bb & ~0x0C) | (i << 2); + if (_p[i].y > bb_top_x()) + _bb = (_bb & ~0x30) | (i << 4); + else if (_p[i].y < bb_bottom_x()) + _bb = (_bb & ~0xC0) | (i << 6); + } +} + + +// +// is_flat, eval +// + +bool +Bezier::is_flat(double t) const throw () +{ + return (_p[2].on_segment(_p[0], _p[3], t) + && _p[1].on_segment(_p[0], _p[3], t)); +} + +static Point +eval_bezier(Point *b_in, int degree, double u) +{ + assert(degree < 4); + Point b[4]; + for (int i = 0; i <= degree; i++) + b[i] = b_in[i]; + + double m = 1.0 - u; + for (int i = 1; i <= degree; i++) + for (int j = 0; j <= degree - i; j++) + b[j] = b[j]*m + b[j+1]*u; + return b[0]; +} + +Point +Bezier::eval(double u) const throw () +{ + Bezier b = *this; + double m = 1.0 - u; + for (int i = 1; i < 4; i++) + for (int j = 0; j < 4 - i; j++) + b._p[j] = m * b._p[j] + u * b._p[j+1]; + return b._p[0]; +} + + +// +// halve +// + +void +Bezier::halve(Bezier &l, Bezier &r) const throw () +{ + Point half = Point::midpoint(_p[1], _p[2]); + l._p[0] = _p[0]; + l._p[1] = Point::midpoint(_p[0], _p[1]); + l._p[2] = Point::midpoint(l._p[1], half); + r._p[3] = _p[3]; + r._p[2] = Point::midpoint(_p[2], _p[3]); + r._p[1] = Point::midpoint(r._p[2], half); + r._p[0] = l._p[3] = Point::midpoint(l._p[2], r._p[1]); +} + + +// +// hit testing +// + +bool +Bezier::in_bb(const Point &p, double tolerance) const throw () +{ + ensure_bb(); + if (bb_right() + tolerance < p.x + || bb_left() - tolerance > p.x + || bb_top() + tolerance < p.y + || bb_bottom() - tolerance > p.y) + return false; + else + return true; +} + +double +Bezier::hit_recurse(const Point &p, double tolerance, double leftd, + double rightd, double leftt, double rightt) const throw () +{ + Bezier left, right; + double middled, resultt; + + if (is_flat(tolerance)) { + if (p.on_segment(_p[0], _p[3], tolerance)) + return (leftt + rightt) / 2; + else + return -1; + } + + if (leftd < tolerance * tolerance) + return leftt; + if (rightd < tolerance * tolerance) + return rightt; + + if (!in_bb(p, tolerance)) + return -1; + + halve(left, right); + middled = (right._p[0] - p).squared_length(); + resultt = left.hit_recurse + (p, tolerance, leftd, middled, leftt, (leftt + rightt) / 2); + if (resultt >= 0) + return resultt; + + return right.hit_recurse + (p, tolerance, middled, rightd, (leftt + rightt) / 2, rightt); +} + +bool +Bezier::hit(const Point &p, double tolerance) const throw () +{ + double leftd = (_p[0] - p).squared_length(); + double rightd = (_p[3] - p).squared_length(); + double resultt = hit_recurse(p, tolerance, leftd, rightd, 0, 1); + return resultt >= 0; +} + + +// +// segmentize to list of points +// +// uses recursive subdivision +// + +void +Bezier::segmentize(Vector<Point> &v, bool first) const +{ + if (is_flat(0.5)) { + if (first) + v.push_back(_p[0]); + v.push_back(_p[3]); + } else { + Bezier left, right; + halve(left, right); + left.segmentize(v, first); + right.segmentize(v, false); + } +} + + +// +// curve fitting +// +// code after Philip J. Schneider's algorithm described, with code, in the +// first Graphics Gems +// + +static void +chord_length_parameterize(const Point *d, int nd, Vector<double> &result) +{ + assert(result.size() == 0); + result.reserve(nd); + result.push_back(0); + for (int i = 1; i < nd; i++) + result.push_back(result.back() + Point::distance(d[i-1], d[i])); + double last_dist = result.back(); + for (int i = 1; i < nd; i++) + result[i] /= last_dist; +} + +static inline double +B0(double u) +{ + double m = 1.0 - u; + return m*m*m; +} + +static inline double +B1(double u) +{ + double m = 1.0 - u; + return 3*m*m*u; +} + +static inline double +B2(double u) +{ + double m = 1.0 - u; + return 3*m*u*u; +} + +static inline double +B3(double u) +{ + return u*u*u; +} + +static Bezier +generate_bezier(const Point *d, int nd, const Vector<double> ¶meters, + const Point &left_tangent, const Point &right_tangent) +{ + Point *a0 = new Point[nd]; + Point *a1 = new Point[nd]; + + for (int i = 0; i < nd; i++) { + a0[i] = left_tangent * B1(parameters[i]); + a1[i] = right_tangent * B2(parameters[i]); + } + + double c[2][2], x[2]; + c[0][0] = c[0][1] = c[1][0] = c[1][1] = x[0] = x[1] = 0.0; + + int last = nd - 1; + for (int i = 0; i < nd; i++) { + c[0][0] += Point::dot(a0[i], a0[i]); + c[0][1] += Point::dot(a0[i], a1[i]); + c[1][1] += Point::dot(a1[i], a1[i]); + + Point tmp = d[i] - (d[0] * (B0(parameters[i]) + B1(parameters[i])) + + d[last] * (B2(parameters[i]) + B3(parameters[i]))); + x[0] += Point::dot(a0[i], tmp); + x[1] += Point::dot(a1[i], tmp); + } + c[1][0] = c[0][1]; + + // compute determinants + double det_c0_c1 = c[0][0]*c[1][1] - c[1][0]*c[0][1]; + double det_c0_x = c[0][0]*x[1] - c[0][1]*x[0]; + double det_x_c1 = x[0]*c[1][1] - x[1]*c[0][1]; + + // finally, derive alpha values + if (det_c0_c1 == 0.0) + det_c0_c1 = c[0][0]*c[1][1] * 10e-12; + double alpha_l = det_x_c1 / det_c0_c1; + double alpha_r = det_c0_x / det_c0_c1; + + // if alpha negative, use the Wu/Barsky heuristic + if (alpha_l < 0.0 || alpha_r < 0.0) { + double distance = Point::distance(d[0], d[last]) / 3; + return Bezier(d[0], d[0] + left_tangent*distance, + d[last] + right_tangent*distance, d[last]); + } else + return Bezier(d[0], d[0] + left_tangent*alpha_l, + d[last] + right_tangent*alpha_r, d[last]); +} + +static double +newton_raphson_root_find(const Bezier &b, const Point &p, double u) +{ + const Point *b_pts = b.points(); + + Point b_det[3]; + for (int i = 0; i < 3; i++) + b_det[i] = (b_pts[i+1] - b_pts[i]) * 3; + + Point b_det_det[2]; + for (int i = 0; i < 2; i++) + b_det_det[i] = (b_det[i+1] - b_det[i]) * 2; + + Point b_u = b.eval(u); + Point b_det_u = eval_bezier(b_det, 2, u); + Point b_det_det_u = eval_bezier(b_det_det, 1, u); + + double numerator = Point::dot(b_u - p, b_det_u); + double denominator = Point::dot(b_det_u, b_det_u) + + Point::dot(b_u - p, b_det_det_u); + + return u - numerator/denominator; +} + +static void +reparameterize(const Point *d, int nd, Vector<double> ¶meters, + const Bezier &b) +{ + for (int i = 0; i < nd; i++) + parameters[i] = newton_raphson_root_find(b, d[i], parameters[i]); +} + +static double +compute_max_error(const Point *d, int nd, const Bezier &b, + const Vector<double> ¶meters, int *split_point) +{ + *split_point = nd/2; + double max_dist = 0.0; + for (int i = 1; i < nd - 1; i++) { + double dist = (b.eval(parameters[i]) - d[i]).squared_length(); + if (dist >= max_dist) { + max_dist = dist; + *split_point = i; + } + } + return max_dist; +} + +static void +fit0(const Point *d, int nd, Point left_tangent, Point right_tangent, + double error, Vector<Bezier> &result) +{ + // Use a heuristic for small regions (only two points) + if (nd == 2) { + double dist = Point::distance(d[0], d[1]) / 3; + result.push_back(Bezier(d[0], + d[0] + dist*left_tangent, + d[1] + dist*right_tangent, + d[1])); + return; + } + + // Parameterize points and attempt to fit curve + Vector<double> parameters; + chord_length_parameterize(d, nd, parameters); + Bezier b = generate_bezier(d, nd, parameters, left_tangent, right_tangent); + + // find max error + int split_point; + double max_error = compute_max_error(d, nd, b, parameters, &split_point); + if (max_error < error) { + result.push_back(b); + return; + } + + // if error not too large, try iteration and reparameterization + if (max_error < error*error) + for (int i = 0; i < 4; i++) { + reparameterize(d, nd, parameters, b); + b = generate_bezier(d, nd, parameters, left_tangent, right_tangent); + max_error = compute_max_error(d, nd, b, parameters, &split_point); + if (max_error < error) { + result.push_back(b); + return; + } + } + + // fitting failed -- split at max error point and fit again + Point center_tangent = ((d[split_point-1] - d[split_point+1])/2).normal(); + fit0(d, split_point+1, left_tangent, center_tangent, error, result); + fit0(d+split_point, nd-split_point, -center_tangent, right_tangent, error, result); +} + +void +Bezier::fit(const Vector<Point> &points, double error, Vector<Bezier> &result) +{ + int npoints = points.size(); + Point left_tangent = (points[1] - points[0]).normal(); + Point right_tangent = (points[npoints-2] - points[npoints-1]).normal(); + fit0(&points[0], npoints, left_tangent, right_tangent, error, result); +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/clp.c b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/clp.c new file mode 100644 index 00000000000..b8aaafd2096 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/clp.c @@ -0,0 +1,2351 @@ +/* -*- related-file-name: "../include/lcdf/clp.h" -*- */ +/* clp.c - Complete source code for CLP. + * This file is part of CLP, the command line parser package. + * + * Copyright (c) 1997-2012 Eddie Kohler, ekohler@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file, which is available in full at + * http://www.pdos.lcs.mit.edu/click/license.html. The conditions include: you + * must preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/clp.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdarg.h> +#include <ctype.h> + +/* By default, assume we have strtoul. */ +#if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H) +# define HAVE_STRTOUL 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @file clp.h + * @brief Functions for parsing command line options. + * + * The CLP functions are used to parse command line arugments into options. + * It automatically handles value parsing, error messages, long options with + * minimum prefix matching, short options, and negated options. + * + * The CLP model works like this. + * + * <ol> + * <li>The user declares an array of Clp_Option structures that define the + * options their program accepts.</li> + * <li>The user creates a Clp_Parser object using Clp_NewParser(), passing in + * the command line arguments to parse and the Clp_Option structures.</li> + * <li>A loop repeatedly calls Clp_Next() to parse the arguments.</li> + * </ol> + * + * Unlike many command line parsing libraries, CLP steps through all arguments + * one at a time, rather than slurping up all options at once. This makes it + * meaningful to give an option more than once. + * + * Here's an example. + * + * @code + * #define ANIMAL_OPT 1 + * #define VEGETABLE_OPT 2 + * #define MINERALS_OPT 3 + * #define USAGE_OPT 4 + * + * static const Clp_Option options[] = { + * { "animal", 'a', ANIMAL_OPT, Clp_ValString, 0 }, + * { "vegetable", 'v', VEGETABLE_OPT, Clp_ValString, Clp_Negate | Clp_Optional }, + * { "minerals", 'm', MINERALS_OPT, Clp_ValInt, 0 }, + * { "usage", 0, USAGE_OPT, 0, 0 } + * }; + * + * int main(int argc, char *argv[]) { + * Clp_Parser *clp = Clp_NewParser(argc, argv, + * sizeof(options) / sizeof(options[0]), options); + * int opt; + * while ((opt = Clp_Next(clp)) != Clp_Done) + * switch (opt) { + * case ANIMAL_OPT: + * fprintf(stderr, "animal is %s\n", clp->val.s); + * break; + * case VEGETABLE_OPT: + * if (clp->negated) + * fprintf(stderr, "no vegetables!\n"); + * else if (clp->have_val) + * fprintf(stderr, "vegetable is %s\n", clp->val.s); + * else + * fprintf(stderr, "vegetables OK\n"); + * break; + * case MINERALS_OPT: + * fprintf(stderr, "%d minerals\n", clp->val.i); + * break; + * case USAGE_OPT: + * fprintf(stderr, "Usage: 20q [--animal=ANIMAL] [--vegetable[=VEGETABLE]] [--minerals=N]\n"); + * break; + * case Clp_NotOption: + * fprintf(stderr, "non-option %s\n", clp->vstr); + * break; + * } + * } + * } + * @endcode + * + * Here are a couple of executions. + * + * <pre> + * % ./20q --animal=cat + * animal is cat + * % ./20q --animal=cat -a dog -afish --animal bird --an=snake + * animal is cat + * animal is dog + * animal is fish + * animal is bird + * animal is snake + * % ./20q --no-vegetables + * no vegetables! + * % ./20q -v + * vegetables OK + * % ./20q -vkale + * vegetable is kale + * % ./20q -m10 + * 10 minerals + * % ./20q -m foo + * '-m' expects an integer, not 'foo' + * </pre> + */ + + +/* Option types for Clp_SetOptionChar */ +#define Clp_DoubledLong (Clp_LongImplicit * 2) + +#define Clp_InitialValType 8 +#define MAX_AMBIGUOUS_VALUES 4 + +typedef struct { + int val_type; + Clp_ValParseFunc func; + int flags; + void *user_data; +} Clp_ValType; + +typedef struct { + unsigned ilong : 1; + unsigned ishort : 1; + unsigned imandatory : 1; + unsigned ioptional : 1; + unsigned ipos : 1; + unsigned ineg : 1; + unsigned iprefmatch : 1; + unsigned lmmpos_short : 1; + unsigned lmmneg_short : 1; + unsigned char ilongoff; + int lmmpos; + int lmmneg; +} Clp_InternOption; + + +#define Clp_OptionCharsSize 5 + +typedef struct { + int c; + int type; +} Clp_Oclass; +#define Clp_OclassSize 10 + +typedef struct Clp_Internal { + const Clp_Option *opt; + Clp_InternOption *iopt; + int nopt; + unsigned opt_generation; + + Clp_ValType *valtype; + int nvaltype; + + const char * const *argv; + int argc; + + Clp_Oclass oclass[Clp_OclassSize]; + int noclass; + int long1pos; + int long1neg; + int utf8; + + char option_chars[Clp_OptionCharsSize]; + const char *xtext; + + const char *program_name; + void (*error_handler)(Clp_Parser *, const char *); + + int option_processing; + int current_option; + + unsigned char is_short; + unsigned char whole_negated; /* true if negated by an option character */ + unsigned char could_be_short; + unsigned char current_short; + unsigned char negated_by_no; + + int ambiguous; + int ambiguous_values[MAX_AMBIGUOUS_VALUES]; +} Clp_Internal; + + +struct Clp_ParserState { + const char * const *argv; + int argc; + + char option_chars[Clp_OptionCharsSize]; + const char *xtext; + + int option_processing; + + unsigned opt_generation; + int current_option; + unsigned char is_short; + unsigned char whole_negated; + unsigned char current_short; + unsigned char negated_by_no; +}; + + +typedef struct Clp_StringList { + + Clp_Option *items; + Clp_InternOption *iopt; + int nitems; + + int allow_int; + int nitems_invalid_report; + +} Clp_StringList; + + +static int parse_string(Clp_Parser *, const char *, int, void *); +static int parse_int(Clp_Parser *, const char *, int, void *); +static int parse_bool(Clp_Parser *, const char *, int, void *); +static int parse_double(Clp_Parser *, const char *, int, void *); +static int parse_string_list(Clp_Parser *, const char *, int, void *); + +static int ambiguity_error(Clp_Parser *, int, int *, const Clp_Option *, + const Clp_InternOption *, const char *, const char *, + ...); + + +/******* + * utf8 + **/ + +#define U_REPLACEMENT 0xFFFD + +static char * +encode_utf8(char *s, int n, int c) +{ + if (c < 0 || c >= 0x110000 || (c >= 0xD800 && c <= 0xDFFF)) + c = U_REPLACEMENT; + if (c <= 0x7F && n >= 1) + *s++ = c; + else if (c <= 0x7FF && n >= 2) { + *s++ = 0xC0 | (c >> 6); + goto char1; + } else if (c <= 0xFFFF && n >= 3) { + *s++ = 0xE0 | (c >> 12); + goto char2; + } else if (n >= 4) { + *s++ = 0xF0 | (c >> 18); + *s++ = 0x80 | ((c >> 12) & 0x3F); + char2: + *s++ = 0x80 | ((c >> 6) & 0x3F); + char1: + *s++ = 0x80 | (c & 0x3F); + } + return s; +} + +static int +decode_utf8(const char *s, const char **cp) +{ + int c; + if ((unsigned char) *s <= 0x7F) /* 1 byte: 0x000000-0x00007F */ + c = *s++; + else if ((unsigned char) *s <= 0xC1) /* bad/overlong encoding */ + goto replacement; + else if ((unsigned char) *s <= 0xDF) { /* 2 bytes: 0x000080-0x0007FF */ + if ((s[1] & 0xC0) != 0x80) /* bad encoding */ + goto replacement; + c = (*s++ & 0x1F) << 6; + goto char1; + } else if ((unsigned char) *s <= 0xEF) { /* 3 bytes: 0x000800-0x00FFFF */ + if ((s[1] & 0xC0) != 0x80 /* bad encoding */ + || (s[2] & 0xC0) != 0x80 /* bad encoding */ + || ((unsigned char) *s == 0xE0 /* overlong encoding */ + && (s[1] & 0xE0) == 0x80) + || ((unsigned char) *s == 0xED /* encoded surrogate */ + && (s[1] & 0xE0) == 0xA0)) + goto replacement; + c = (*s++ & 0x0F) << 12; + goto char2; + } else if ((unsigned char) *s <= 0xF4) { /* 4 bytes: 0x010000-0x10FFFF */ + if ((s[1] & 0xC0) != 0x80 /* bad encoding */ + || (s[2] & 0xC0) != 0x80 /* bad encoding */ + || (s[3] & 0xC0) != 0x80 /* bad encoding */ + || ((unsigned char) *s == 0xF0 /* overlong encoding */ + && (s[1] & 0xF0) == 0x80) + || ((unsigned char) *s == 0xF4 /* encoded value > 0x10FFFF */ + && (unsigned char) s[1] >= 0x90)) + goto replacement; + c = (*s++ & 0x07) << 18; + c += (*s++ & 0x3F) << 12; + char2: + c += (*s++ & 0x3F) << 6; + char1: + c += (*s++ & 0x3F); + } else { + replacement: + c = U_REPLACEMENT; + for (s++; (*s & 0xC0) == 0x80; s++) + /* nothing */; + } + if (cp) + *cp = s; + return c; +} + +static int +utf8_charlen(const char *s) +{ + const char *sout; + (void) decode_utf8(s, &sout); + return sout - s; +} + +static int +clp_utf8_charlen(const Clp_Internal *cli, const char *s) +{ + return (cli->utf8 ? utf8_charlen(s) : 1); +} + + +/******* + * Clp_NewParser, etc. + **/ + +static int +min_different_chars(const char *s, const char *t) + /* Returns the minimum number of bytes required to distinguish + s from t. + If s is shorter than t, returns strlen(s). */ +{ + const char *sfirst = s; + while (*s && *t && *s == *t) + s++, t++; + if (!*s) + return s - sfirst; + else + return s - sfirst + 1; +} + +static int +long_as_short(const Clp_Internal *cli, const Clp_Option *o, + Clp_InternOption *io, int failure) +{ + if ((cli->long1pos || cli->long1neg) && io->ilong) { + const char *name = o->long_name + io->ilongoff; + if (cli->utf8) { + int c = decode_utf8(name, &name); + if (!*name && c && c != U_REPLACEMENT) + return c; + } else if (name[0] && !name[1]) + return (unsigned char) name[0]; + } + return failure; +} + +static void +compare_options(Clp_Parser *clp, const Clp_Option *o1, Clp_InternOption *io1, + const Clp_Option *o2, Clp_InternOption *io2) +{ + Clp_Internal *cli = clp->internal; + int short1, shortx1; + + /* ignore meaningless combinations */ + if ((!io1->ishort && !io1->ilong) || (!io2->ishort && !io2->ilong) + || !((io1->ipos && io2->ipos) || (io1->ineg && io2->ineg)) + || o1->option_id == o2->option_id) + return; + + /* look for duplication of short options */ + short1 = (io1->ishort ? o1->short_name : -1); + shortx1 = long_as_short(cli, o1, io1, -2); + if (short1 >= 0 || shortx1 >= 0) { + int short2 = (io2->ishort ? o2->short_name : -3); + int shortx2 = long_as_short(cli, o2, io2, -4); + if (short1 == short2) + Clp_OptionError(clp, "CLP internal error: more than 1 option has short name %<%c%>", short1); + else if ((short1 == shortx2 || shortx1 == short2 || shortx1 == shortx2) + && ((io1->ipos && io2->ipos && cli->long1pos) + || (io1->ineg && io2->ineg && cli->long1neg))) + Clp_OptionError(clp, "CLP internal error: 1-char long name conflicts with short name %<%c%>", (short1 == shortx2 ? shortx2 : shortx1)); + } + + /* analyze longest minimum match */ + if (io1->ilong) { + const char *name1 = o1->long_name + io1->ilongoff; + + /* long name's first character matches short name */ + if (io2->ishort && !io1->iprefmatch) { + int name1char = (cli->utf8 ? decode_utf8(name1, 0) : (unsigned char) *name1); + if (name1char == o2->short_name) { + if (io1->ipos && io2->ipos) + io1->lmmpos_short = 1; + if (io1->ineg && io2->ineg) + io1->lmmneg_short = 1; + } + } + + /* match long name to long name */ + if (io2->ilong) { + const char *name2 = o2->long_name + io2->ilongoff; + if (strcmp(name1, name2) == 0) + Clp_OptionError(clp, "CLP internal error: duplicate long name %<%s%>", name1); + if (io1->ipos && io2->ipos && !strncmp(name1, name2, io1->lmmpos) + && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) + io1->lmmpos = min_different_chars(name1, name2); + if (io1->ineg && io2->ineg && !strncmp(name1, name2, io1->lmmneg) + && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) + io1->lmmneg = min_different_chars(name1, name2); + } + } +} + +/** @param argc number of arguments + * @param argv argument array + * @param nopt number of option definitions + * @param opt option definition array + * @return the parser + * + * The new Clp_Parser that will parse the arguments in @a argv according to + * the option definitions in @a opt. + * + * The Clp_Parser is created with the following characteristics: + * + * <ul> + * <li>The "-" character introduces short options (<tt>Clp_SetOptionChar(clp, + * '-', Clp_Short)</tt>).</li> + * <li>Clp_ProgramName is set from the first argument in @a argv, if any. The + * first argument returned by Clp_Next() will be the second argument in @a + * argv. Note that this behavior differs from Clp_SetArguments.</li> + * <li>UTF-8 support is on iff the <tt>LANG</tt> environment variable contains + * one of the substrings "UTF-8", "UTF8", or "utf8". Override this with + * Clp_SetUTF8().</li> + * <li>The Clp_ValString, Clp_ValStringNotOption, Clp_ValInt, Clp_ValUnsigned, + * Clp_ValBool, and Clp_ValDouble types are installed.</li> + * <li>Errors are reported to standard error.</li> + * </ul> + * + * You may also create a Clp_Parser with no arguments or options + * (<tt>Clp_NewParser(0, 0, 0, 0)</tt>) and set the arguments and options + * later. + * + * Returns NULL if there isn't enough memory to construct the parser. + * + * @note The CLP library will not modify the contents of @a argv or @a opt. + * The calling program must not modify @a opt. It may modify @a argv in + * limited cases. + */ +Clp_Parser * +Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt) +{ + Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser)); + Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal)); + Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); + if (cli) + cli->valtype = (Clp_ValType *)malloc(sizeof(Clp_ValType) * Clp_InitialValType); + if (!clp || !cli || !iopt || !cli->valtype) + goto failed; + + clp->opt = -1; + clp->negated = 0; + clp->have_val = 0; + clp->vstr = 0; + clp->user_data = 0; + clp->internal = cli; + + cli->opt = opt; + cli->nopt = nopt; + cli->iopt = iopt; + cli->opt_generation = 0; + cli->error_handler = 0; + + /* Assign program name (now so we can call Clp_OptionError) */ + if (argc > 0) { + const char *slash = strrchr(argv[0], '/'); + cli->program_name = slash ? slash + 1 : argv[0]; + } else + cli->program_name = 0; + + /* Assign arguments, skipping program name */ + Clp_SetArguments(clp, argc - 1, argv + 1); + + /* Initialize UTF-8 status and option classes */ + { + char *s = getenv("LANG"); + cli->utf8 = (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0 + || strstr(s, "utf8") != 0)); + } + cli->oclass[0].c = '-'; + cli->oclass[0].type = Clp_Short; + cli->noclass = 1; + cli->long1pos = cli->long1neg = 0; + + /* Add default type parsers */ + cli->nvaltype = 0; + Clp_AddType(clp, Clp_ValString, 0, parse_string, 0); + Clp_AddType(clp, Clp_ValStringNotOption, Clp_DisallowOptions, parse_string, 0); + Clp_AddType(clp, Clp_ValInt, 0, parse_int, 0); + Clp_AddType(clp, Clp_ValUnsigned, 0, parse_int, (void *)cli); + Clp_AddType(clp, Clp_ValBool, 0, parse_bool, 0); + Clp_AddType(clp, Clp_ValDouble, 0, parse_double, 0); + + /* Set options */ + Clp_SetOptions(clp, nopt, opt); + + return clp; + + failed: + if (cli && cli->valtype) + free(cli->valtype); + if (cli) + free(cli); + if (clp) + free(clp); + if (iopt) + free(iopt); + return 0; +} + +/** @param clp the parser + * + * All memory associated with @a clp is freed. */ +void +Clp_DeleteParser(Clp_Parser *clp) +{ + int i; + Clp_Internal *cli; + if (!clp) + return; + + cli = clp->internal; + + /* get rid of any string list types */ + for (i = 0; i < cli->nvaltype; i++) + if (cli->valtype[i].func == parse_string_list) { + Clp_StringList *clsl = (Clp_StringList *)cli->valtype[i].user_data; + free(clsl->items); + free(clsl->iopt); + free(clsl); + } + + free(cli->valtype); + free(cli->iopt); + free(cli); + free(clp); +} + + +/** @param clp the parser + * @param errh error handler function + * @return previous error handler function + * + * The error handler function is called when CLP encounters an error while + * parsing the command line. It is called with the arguments "<tt>(*errh)(@a + * clp, s)</tt>", where <tt>s</tt> is a description of the error terminated by + * a newline. The <tt>s</tt> descriptions produced by CLP itself are prefixed + * by the program name, if any. */ +Clp_ErrorHandler +Clp_SetErrorHandler(Clp_Parser *clp, void (*errh)(Clp_Parser *, const char *)) +{ + Clp_Internal *cli = clp->internal; + Clp_ErrorHandler old = cli->error_handler; + cli->error_handler = errh; + return old; +} + +/** @param clp the parser + * @param utf8 does the parser support UTF-8? + * @return previous UTF-8 mode + * + * In UTF-8 mode, all input strings (arguments and long names for options) are + * assumed to be encoded via UTF-8, and all character names + * (Clp_SetOptionChar() and short names for options) may cover the whole + * Unicode range. Out of UTF-8 mode, all input strings are treated as binary, + * and all character names must be unsigned char values. + * + * Furthermore, error messages in UTF-8 mode may contain Unicode quote + * characters. */ +int +Clp_SetUTF8(Clp_Parser *clp, int utf8) +{ + Clp_Internal *cli = clp->internal; + int i, j, old_utf8 = cli->utf8; + cli->utf8 = utf8; + for (i = 0; i < cli->nopt; ++i) { + cli->iopt[i].lmmpos = cli->iopt[i].lmmneg = 1; + cli->iopt[i].lmmpos_short = cli->iopt[i].lmmneg_short = 0; + for (j = 0; j < cli->nopt; ++j) + compare_options(clp, &cli->opt[i], &cli->iopt[i], + &cli->opt[j], &cli->iopt[j]); + } + return old_utf8; +} + +/** @param clp the parser + * @param c character + * @return option character treatment + * + * Returns an integer specifying how CLP treats arguments that begin + * with character @a c. See Clp_SetOptionChar for possibilities. + */ +int +Clp_OptionChar(Clp_Parser *clp, int c) +{ + Clp_Internal *cli = clp->internal; + int i, oclass = 0; + if (cli->noclass > 0 && cli->oclass[0].c == 0) + oclass = cli->oclass[0].type; + for (i = 0; i < cli->noclass; ++i) + if (cli->oclass[i].c == c) + oclass = cli->oclass[i].type; + return oclass; +} + +/** @param clp the parser + * @param c character + * @param type option character treatment + * @return previous option character treatment, or -1 on error + * + * @a type specifies how CLP treats arguments that begin with character @a c. + * Possibilities are: + * + * <dl> + * <dt>Clp_NotOption (or 0)</dt> + * <dd>The argument cannot be an option.</dd> + * <dt>Clp_Long</dt> + * <dd>The argument is a long option.</dd> + * <dt>Clp_Short</dt> + * <dd>The argument is a set of short options.</dd> + * <dt>Clp_Short|Clp_Long</dt> + * <dd>The argument is either a long option or, if no matching long option is + * found, a set of short options.</dd> + * <dt>Clp_LongNegated</dt> + * <dd>The argument is a negated long option. For example, after + * Clp_SetOptionChar(@a clp, '^', Clp_LongNegated), the argument "^foo" is + * equivalent to "--no-foo".</dd> + * <dt>Clp_ShortNegated</dt> + * <dd>The argument is a set of negated short options.</dd> + * <dt>Clp_ShortNegated|Clp_LongNegated</dt> + * <dd>The argument is either a negated long option or, if no matching long + * option is found, a set of negated short options.</dd> + * <dt>Clp_LongImplicit</dt> + * <dd>The argument may be a long option, where the character @a c is actually + * part of the long option name. For example, after Clp_SetOptionChar(@a clp, + * 'f', Clp_LongImplicit), the argument "foo" may be equivalent to + * "--foo".</dd> + * </dl> + * + * In UTF-8 mode, @a c may be any Unicode character. Otherwise, @a c must be + * an unsigned char value. The special character 0 assigns @a type to @em + * every character. + * + * It is an error if @a c is out of range, @a type is illegal, or there are + * too many character definitions stored in @a clp already. The function + * returns -1 on error. + * + * A double hyphen "--" always introduces a long option. This behavior cannot + * currently be changed with Clp_SetOptionChar(). + */ +int +Clp_SetOptionChar(Clp_Parser *clp, int c, int type) +{ + int i, j, long1pos, long1neg; + int old = Clp_OptionChar(clp, c); + Clp_Internal *cli = clp->internal; + + if (type != Clp_NotOption && type != Clp_Short && type != Clp_Long + && type != Clp_ShortNegated && type != Clp_LongNegated + && type != Clp_LongImplicit && type != (Clp_Short | Clp_Long) + && type != (Clp_ShortNegated | Clp_LongNegated)) + return -1; + if (c < 0 || c >= (cli->utf8 ? 0x110000 : 256)) + return -1; + + if (c == 0) + cli->noclass = 0; + for (i = 0; i < cli->noclass; ++i) + if (cli->oclass[i].c == c) + break; + if (i == Clp_OclassSize) + return -1; + + cli->oclass[i].c = c; + cli->oclass[i].type = type; + if (cli->noclass == i) + cli->noclass = i + 1; + + long1pos = long1neg = 0; + for (i = 0; i < cli->noclass; ++i) { + if ((cli->oclass[i].type & Clp_Short) + && (cli->oclass[i].type & Clp_Long)) + long1pos = 1; + if ((cli->oclass[i].type & Clp_ShortNegated) + && (cli->oclass[i].type & Clp_LongNegated)) + long1neg = 1; + } + + if (long1pos != cli->long1pos || long1neg != cli->long1neg) { + /* Must recheck option set */ + cli->long1pos = long1pos; + cli->long1neg = long1neg; + for (i = 0; i < cli->nopt; ++i) { + cli->iopt[i].lmmpos = cli->iopt[i].lmmneg = 1; + cli->iopt[i].lmmpos_short = cli->iopt[i].lmmneg_short = 0; + for (j = 0; j < cli->nopt; ++j) + compare_options(clp, &cli->opt[i], &cli->iopt[i], + &cli->opt[j], &cli->iopt[j]); + } + } + + return old; +} + +/** @param clp the parser + * @param nopt number of option definitions + * @param opt option definition array + * @return 0 on success, -1 on failure + * + * Installs the option definitions in @a opt. Future option parsing will + * use @a opt to search for options. + * + * Also checks @a opt's option definitions for validity. "CLP internal + * errors" are reported via Clp_OptionError() if: + * + * <ul> + * <li>An option has a negative ID.</li> + * <li>Two different short options have the same name.</li> + * <li>Two different long options have the same name.</li> + * <li>A short and a long option are ambiguous, in that some option character + * might introduce either a short or a long option (e.g., Clp_SetOptionChar(@a + * clp, '-', Clp_Long|Clp_Short)), and a short name equals a long name.</li> + * </ul> + * + * If necessary memory cannot be allocated, this function returns -1 without + * modifying the parser. + * + * @note The CLP library will not modify the contents of @a argv or @a opt. + * The calling program must not modify @a opt either until another call to + * Clp_SetOptions() or the parser is destroyed. + */ +int +Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt) +{ + Clp_Internal *cli = clp->internal; + Clp_InternOption *iopt; + int i, j; + static unsigned opt_generation = 0; + + if (nopt > cli->nopt) { + iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); + if (!iopt) + return -1; + free(cli->iopt); + cli->iopt = iopt; + } + + cli->opt = opt; + cli->nopt = nopt; + cli->opt_generation = ++opt_generation; + iopt = cli->iopt; + cli->current_option = -1; + + /* Massage the options to make them usable */ + for (i = 0; i < nopt; i++) { + /* Ignore negative option_ids, which are internal to CLP */ + if (opt[i].option_id < 0) { + Clp_OptionError(clp, "CLP internal error: option %d has negative option_id", i); + iopt[i].ilong = iopt[i].ishort = iopt[i].ipos = iopt[i].ineg = 0; + continue; + } + + /* Set flags based on input flags */ + iopt[i].ilong = (opt[i].long_name != 0 && opt[i].long_name[0] != 0); + iopt[i].ishort = (opt[i].short_name > 0 + && opt[i].short_name < (cli->utf8 ? 0x110000 : 256)); + iopt[i].ipos = 1; + iopt[i].ineg = (opt[i].flags & Clp_Negate) != 0; + iopt[i].imandatory = (opt[i].flags & Clp_Mandatory) != 0; + iopt[i].ioptional = (opt[i].flags & Clp_Optional) != 0; + iopt[i].iprefmatch = (opt[i].flags & Clp_PreferredMatch) != 0; + iopt[i].ilongoff = 0; + + /* Enforce invariants */ + if (opt[i].val_type <= 0) + iopt[i].imandatory = iopt[i].ioptional = 0; + if (opt[i].val_type > 0 && !iopt[i].ioptional) + iopt[i].imandatory = 1; + + /* Options that start with 'no-' should be changed to OnlyNegated */ + if (iopt[i].ilong && strncmp(opt[i].long_name, "no-", 3) == 0) { + iopt[i].ipos = 0; + iopt[i].ineg = 1; + iopt[i].ilongoff = 3; + if (strncmp(opt[i].long_name + 3, "no-", 3) == 0) + Clp_OptionError(clp, "CLP internal error: option %d begins with \"no-no-\"", i); + } else if (opt[i].flags & Clp_OnlyNegated) { + iopt[i].ipos = 0; + iopt[i].ineg = 1; + } + } + + /* Check option set */ + for (i = 0; i < nopt; ++i) { + iopt[i].lmmpos = iopt[i].lmmneg = 1; + iopt[i].lmmpos_short = iopt[i].lmmneg_short = 0; + for (j = 0; j < nopt; ++j) + compare_options(clp, &opt[i], &iopt[i], &opt[j], &iopt[j]); + } + + return 0; +} + +/** @param clp the parser + * @param argc number of arguments + * @param argv argument array + * + * Installs the arguments in @a argv for parsing. Future option parsing will + * analyze @a argv. + * + * Unlike Clp_NewParser(), this function does not treat @a argv[0] specially. + * The first subsequent call to Clp_Next() will analyze @a argv[0]. + * + * This function also sets option processing to on, as by + * Clp_SetOptionProcessing(@a clp, 1). + * + * @note The CLP library will not modify the contents of @a argv. The calling + * program should not generally modify the element of @a argv that CLP is + * currently analyzing. + */ +void +Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv) +{ + Clp_Internal *cli = clp->internal; + + cli->argc = argc + 1; + cli->argv = argv - 1; + + cli->is_short = 0; + cli->whole_negated = 0; + cli->option_processing = 1; + cli->current_option = -1; +} + + +/** @param clp the parser + * @param on whether to search for options + * @return previous option processing setting + * + * When option processing is off, every call to Clp_Next() returns + * Clp_NotOption. By default the option <tt>"--"</tt> turns off option + * processing and is otherwise ignored. + */ +int +Clp_SetOptionProcessing(Clp_Parser *clp, int on) +{ + Clp_Internal *cli = clp->internal; + int old = cli->option_processing; + cli->option_processing = on; + return old; +} + + +/******* + * functions for Clp_Option lists + **/ + +/* the ever-glorious argcmp */ + +static int +argcmp(const char *ref, const char *arg, int min_match, int fewer_dashes) + /* Returns 0 if ref and arg don't match. + Returns -1 if ref and arg match, but fewer than min_match characters. + Returns len if ref and arg match min_match or more characters; + len is the number of characters that matched in arg. + Allows arg to contain fewer dashes than ref iff fewer_dashes != 0. + + Examples: + argcmp("x", "y", 1, 0) --> 0 / just plain wrong + argcmp("a", "ax", 1, 0) --> 0 / ...even though min_match == 1 + and the 1st chars match + argcmp("box", "bo", 3, 0) --> -1 / ambiguous + argcmp("cat", "c=3", 1, 0) --> 1 / handles = arguments + */ +{ + const char *refstart = ref; + const char *argstart = arg; + assert(min_match > 0); + + compare: + while (*ref && *arg && *arg != '=' && *ref == *arg) + ref++, arg++; + + /* Allow arg to contain fewer dashes than ref */ + if (fewer_dashes && *ref == '-' && ref[1] && ref[1] == *arg) { + ref++; + goto compare; + } + + if (*arg && *arg != '=') + return 0; + else if (ref - refstart < min_match) + return -1; + else + return arg - argstart; +} + +static int +find_prefix_opt(Clp_Parser *clp, const char *arg, + int nopt, const Clp_Option *opt, + const Clp_InternOption *iopt, + int *ambiguous, int *ambiguous_values) + /* Looks for an unambiguous match of 'arg' against one of the long + options in 'opt'. Returns positive if it finds one; otherwise, returns + -1 and possibly changes 'ambiguous' and 'ambiguous_values' to keep + track of at most MAX_AMBIGUOUS_VALUES possibilities. */ +{ + int i, fewer_dashes = 0, first_ambiguous = *ambiguous; + int negated = clp && clp->negated; + int first_charlen = (clp ? clp_utf8_charlen(clp->internal, arg) : 1); + + retry: + for (i = 0; i < nopt; i++) { + int len, lmm; + if (!iopt[i].ilong || (negated ? !iopt[i].ineg : !iopt[i].ipos)) + continue; + + lmm = (negated ? iopt[i].lmmneg : iopt[i].lmmpos); + if (clp && clp->internal->could_be_short + && (negated ? iopt[i].lmmneg_short : iopt[i].lmmpos_short)) + lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); + len = argcmp(opt[i].long_name + iopt[i].ilongoff, arg, lmm, fewer_dashes); + if (len > 0) + return i; + else if (len < 0) { + if (*ambiguous < MAX_AMBIGUOUS_VALUES) + ambiguous_values[*ambiguous] = i; + (*ambiguous)++; + } + } + + /* If there were no partial matches, try again with fewer_dashes true */ + if (*ambiguous == first_ambiguous && !fewer_dashes) { + fewer_dashes = 1; + goto retry; + } + + return -1; +} + + +/***** + * Argument parsing + **/ + +static int +val_type_binsearch(Clp_Internal *cli, int val_type) +{ + unsigned l = 0, r = cli->nvaltype; + while (l < r) { + unsigned m = l + (r - l) / 2; + if (cli->valtype[m].val_type == val_type) + return m; + else if (cli->valtype[m].val_type < val_type) + l = m + 1; + else + r = m; + } + return l; +} + +/** @param clp the parser + * @param val_type value type ID + * @param flags value type flags + * @param parser parser function + * @param user_data user data for @a parser function + * @return 0 on success, -1 on failure + * + * Defines argument type @a val_type in parser @a clp. The parsing function + * @a parser will be passed argument values for type @a val_type. It should + * parse the argument into values (usually in @a clp->val, but sometimes + * elsewhere), report errors if necessary, and return whether the parse was + * successful. + * + * Any prior argument parser match @a val_type is removed. @a val_type must + * be greater than zero. + * + * @a flags specifies additional parsing flags. At the moment the only + * relevant flag is Clp_DisallowOptions, which means that separated values + * must not look like options. For example, assume argument + * <tt>--a</tt>/<tt>-a</tt> has mandatory value type Clp_ValStringNotOption + * (which has Clp_DisallowOptions). Then: + * + * <ul> + * <li><tt>--a=--b</tt> will parse with value <tt>--b</tt>.</li> + * <li><tt>-a--b</tt> will parse with value <tt>--b</tt>.</li> + * <li><tt>--a --b</tt> will not parse, since the mandatory value looks like + * an option.</li> + * <li><tt>-a --b</tt> will not parse, since the mandatory value looks like + * an option.</li> + * </ul> + */ +int +Clp_AddType(Clp_Parser *clp, int val_type, int flags, + Clp_ValParseFunc parser, void *user_data) +{ + Clp_Internal *cli = clp->internal; + int vtpos; + + if (val_type <= 0 || !parser) + return -1; + + vtpos = val_type_binsearch(cli, val_type); + + if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != val_type) { + if (cli->nvaltype != 0 && (cli->nvaltype % Clp_InitialValType) == 0) { + Clp_ValType *new_valtype = + (Clp_ValType *) realloc(cli->valtype, sizeof(Clp_ValType) * (cli->nvaltype + Clp_InitialValType)); + if (!new_valtype) + return -1; + cli->valtype = new_valtype; + } + memmove(&cli->valtype[vtpos + 1], &cli->valtype[vtpos], + sizeof(Clp_ValType) * (cli->nvaltype - vtpos)); + cli->nvaltype++; + cli->valtype[vtpos].func = 0; + } + + if (cli->valtype[vtpos].func == parse_string_list) { + Clp_StringList *clsl = (Clp_StringList *) cli->valtype[vtpos].user_data; + free(clsl->items); + free(clsl->iopt); + free(clsl); + } + + cli->valtype[vtpos].val_type = val_type; + cli->valtype[vtpos].func = parser; + cli->valtype[vtpos].flags = flags; + cli->valtype[vtpos].user_data = user_data; + return 0; +} + + +/******* + * Default argument parsers + **/ + +static int +parse_string(Clp_Parser *clp, const char *arg, int complain, void *user_data) +{ + (void)complain, (void)user_data; + clp->val.s = arg; + return 1; +} + +static int +parse_int(Clp_Parser *clp, const char *arg, int complain, void *user_data) +{ + const char *val; + if (*arg == 0 || isspace((unsigned char) *arg) + || (user_data != 0 && *arg == '-')) + val = arg; + else if (user_data != 0) { /* unsigned */ +#if HAVE_STRTOUL + clp->val.u = strtoul(arg, (char **) &val, 0); +#else + /* don't bother really trying to do it right */ + if (arg[0] == '-') + val = arg; + else + clp->val.u = strtol(arg, (char **) &val, 0); +#endif + } else + clp->val.i = strtol(arg, (char **) &val, 0); + if (*arg != 0 && *val == 0) + return 1; + else if (complain) { + const char *message = user_data != 0 + ? "%<%O%> expects a nonnegative integer, not %<%s%>" + : "%<%O%> expects an integer, not %<%s%>"; + return Clp_OptionError(clp, message, arg); + } else + return 0; +} + +static int +parse_double(Clp_Parser *clp, const char *arg, int complain, void *user_data) +{ + const char *val; + (void)user_data; + if (*arg == 0 || isspace((unsigned char) *arg)) + val = arg; + else + clp->val.d = strtod(arg, (char **) &val); + if (*arg != 0 && *val == 0) + return 1; + else if (complain) + return Clp_OptionError(clp, "%<%O%> expects a real number, not %<%s%>", arg); + else + return 0; +} + +static int +parse_bool(Clp_Parser *clp, const char *arg, int complain, void *user_data) +{ + int i; + char lcarg[6]; + (void)user_data; + if (strlen(arg) > 5 || strchr(arg, '=') != 0) + goto error; + + for (i = 0; arg[i] != 0; i++) + lcarg[i] = tolower((unsigned char) arg[i]); + lcarg[i] = 0; + + if (argcmp("yes", lcarg, 1, 0) > 0 + || argcmp("true", lcarg, 1, 0) > 0 + || argcmp("1", lcarg, 1, 0) > 0) { + clp->val.i = 1; + return 1; + } else if (argcmp("no", lcarg, 1, 0) > 0 + || argcmp("false", lcarg, 1, 0) > 0 + || argcmp("1", lcarg, 1, 0) > 0) { + clp->val.i = 0; + return 1; + } + + error: + if (complain) + Clp_OptionError(clp, "%<%O%> expects a true-or-false value, not %<%s%>", arg); + return 0; +} + + +/***** + * Clp_AddStringListType + **/ + +static int +parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *user_data) +{ + Clp_StringList *sl = (Clp_StringList *)user_data; + int idx, ambiguous = 0; + int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1]; + + /* actually look for a string value */ + idx = find_prefix_opt + (0, arg, sl->nitems, sl->items, sl->iopt, + &ambiguous, ambiguous_values); + if (idx >= 0) { + clp->val.i = sl->items[idx].option_id; + return 1; + } + + if (sl->allow_int) { + if (parse_int(clp, arg, 0, 0)) + return 1; + } + + if (complain) { + const char *complaint; + if (ambiguous) + complaint = "ambiguous value %<%s%> for option %<%O%>"; + else { + complaint = "unknown value %<%s%> for option %<%O%>"; + ambiguous = sl->nitems_invalid_report; + for (idx = 0; idx < ambiguous; idx++) + ambiguous_values[idx] = idx; + } + return ambiguity_error + (clp, ambiguous, ambiguous_values, sl->items, sl->iopt, + "", complaint, arg); + } else + return 0; +} + + +static int +finish_string_list(Clp_Parser *clp, int val_type, int flags, + Clp_Option *items, int nitems, int itemscap) +{ + int i, j; + Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList)); + Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nitems); + if (!clsl || !iopt) + goto error; + + clsl->items = items; + clsl->iopt = iopt; + clsl->nitems = nitems; + clsl->allow_int = (flags & Clp_AllowNumbers) != 0; + + if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) { + items[nitems].long_name = "any integer"; + clsl->nitems_invalid_report = nitems + 1; + } else if (nitems > MAX_AMBIGUOUS_VALUES + 1) + clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1; + else + clsl->nitems_invalid_report = nitems; + + for (i = 0; i < nitems; i++) { + iopt[i].ilong = iopt[i].ipos = 1; + iopt[i].ishort = iopt[i].ineg = iopt[i].ilongoff = iopt[i].iprefmatch = 0; + iopt[i].lmmpos = 1; + iopt[i].lmmpos_short = 0; + } + for (i = 0; i < nitems; i++) + for (j = 0; j < nitems; j++) + compare_options(clp, &items[i], &iopt[i], &items[j], &iopt[j]); + + if (Clp_AddType(clp, val_type, 0, parse_string_list, clsl) >= 0) + return 0; + + error: + if (clsl) + free(clsl); + if (iopt) + free(iopt); + return -1; +} + +/** @param clp the parser + * @param val_type value type ID + * @param flags string list flags + * @return 0 on success, -1 on failure + * + * Defines argument type @a val_type in parser @a clp. The parsing function + * sets @a clp->val.i to an integer. The value string is matched against + * strings provided in the ellipsis arguments. For example, the + * Clp_AddStringListType() call below has the same effect as the + * Clp_AddStringListTypeVec() call: + * + * For example: + * @code + * Clp_AddStringListType(clp, 100, Clp_AllowNumbers, "cat", 1, + * "cattle", 2, "dog", 3, (const char *) NULL); + * + * const char * const strs[] = { "cat", "cattle", "dog" }; + * const int vals[] = { 1, 2, 3 }; + * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); + * @endcode + * + * @note The CLP library will not modify any of the passed-in strings. The + * calling program must not modify or free them either until the parser is + * destroyed. + */ +int +Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) +{ + int nitems = 0; + int itemscap = 5; + Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); + + va_list val; + va_start(val, flags); + + if (!items) + goto error; + + /* slurp up the arguments */ + while (1) { + int value; + char *name = va_arg(val, char *); + if (!name) + break; + value = va_arg(val, int); + + if (nitems >= itemscap) { + Clp_Option *new_items; + itemscap *= 2; + new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap); + if (!new_items) + goto error; + items = new_items; + } + + items[nitems].long_name = name; + items[nitems].option_id = value; + items[nitems].flags = 0; + nitems++; + } + + va_end(val); + if (finish_string_list(clp, val_type, flags, items, nitems, itemscap) >= 0) + return 0; + + error: + va_end(val); + if (items) + free(items); + return -1; +} + +/** @param clp the parser + * @param val_type value type ID + * @param flags string list flags + * @param nstrs number of strings in list + * @param strs array of strings + * @param vals array of values + * @return 0 on success, -1 on failure + * + * Defines argument type @a val_type in parser @a clp. The parsing function + * sets @a clp->val.i to an integer. The value string is matched against the + * @a strs. If there's a unique match, the corresponding entry from @a vals + * is returned. Unique prefix matches also work. Finally, if @a flags + * contains the Clp_AllowNumbers flag, then integers are also accepted. + * + * For example: + * @code + * const char * const strs[] = { "cat", "cattle", "dog" }; + * const int vals[] = { 1, 2, 3 }; + * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); + * @endcode + * + * Say that option <tt>--animal</tt> takes value type 100. Then: + * + * <ul> + * <li><tt>--animal=cat</tt> will succeed and set @a clp->val.i = 1.</li> + * <li><tt>--animal=cattle</tt> will succeed and set @a clp->val.i = 2.</li> + * <li><tt>--animal=dog</tt> will succeed and set @a clp->val.i = 3.</li> + * <li><tt>--animal=d</tt> will succeed and set @a clp->val.i = 3.</li> + * <li><tt>--animal=c</tt> will fail, since <tt>c</tt> is ambiguous.</li> + * <li><tt>--animal=4</tt> will succeed and set @a clp->val.i = 4.</li> + * </ul> + * + * @note The CLP library will not modify the contents of @a strs or @a vals. + * The calling program can modify the @a strs array, but the actual strings + * (for instance, @a strs[0] and @a strs[1]) must not be modified or freed + * until the parser is destroyed. + */ +int +Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, + int nstrs, const char * const *strs, + const int *vals) + /* An alternate way to make a string list type. See Clp_AddStringListType + for the basics; this coalesces the strings and values into two arrays, + rather than spreading them out into a variable argument list. */ +{ + int i; + int itemscap = (nstrs < 5 ? 5 : nstrs); + Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); + if (!items) + return -1; + + /* copy over items */ + for (i = 0; i < nstrs; i++) { + items[i].long_name = strs[i]; + items[i].option_id = vals[i]; + items[i].flags = 0; + } + + if (finish_string_list(clp, val_type, flags, items, nstrs, itemscap) >= 0) + return 0; + else { + free(items); + return -1; + } +} + + +/******* + * Returning information + **/ + +const char * +Clp_ProgramName(Clp_Parser *clp) +{ + return clp->internal->program_name; +} + +/** @param clp the parser + * @param name new program name + * @return previous program name + * + * The calling program should not modify or free @a name until @a clp itself + * is destroyed. */ +const char * +Clp_SetProgramName(Clp_Parser *clp, const char *name) +{ + const char *old = clp->internal->program_name; + clp->internal->program_name = name; + return old; +} + + +/****** + * Clp_ParserStates + **/ + +/** @return the parser state + * + * A Clp_ParserState object can store a parsing state of a Clp_Parser object. + * This state specifies exactly how far the Clp_Parser has gotten in parsing + * an argument list. The Clp_SaveParser() and Clp_RestoreParser() functions + * can be used to save this state and then restore it later, allowing a + * Clp_Parser to switch among argument lists. + * + * The initial state is empty, in that after Clp_RestoreParser(clp, state), + * Clp_Next(clp) would return Clp_Done. + * + * Parser states can be saved and restored among different parser objects. + * + * @sa Clp_DeleteParserState, Clp_SaveParser, Clp_RestoreParser + */ +Clp_ParserState * +Clp_NewParserState(void) +{ + Clp_ParserState *state = (Clp_ParserState *)malloc(sizeof(Clp_ParserState)); + if (state) { + state->argv = 0; + state->argc = 0; + state->option_chars[0] = 0; + state->xtext = 0; + state->option_processing = 0; + state->opt_generation = 0; + state->current_option = -1; + state->is_short = 0; + state->whole_negated = 0; + state->current_short = 0; + state->negated_by_no = 0; + } + return state; +} + +/** @param state parser state + * + * The memory associated with @a state is freed. + */ +void +Clp_DeleteParserState(Clp_ParserState *state) +{ + free(state); +} + +/** @param clp the parser + * @param state parser state + * @sa Clp_NewParserState, Clp_RestoreParser + */ +void +Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state) +{ + Clp_Internal *cli = clp->internal; + state->argv = cli->argv; + state->argc = cli->argc; + memcpy(state->option_chars, cli->option_chars, Clp_OptionCharsSize); + state->xtext = cli->xtext; + + state->option_processing = cli->option_processing; + state->opt_generation = cli->opt_generation; + state->current_option = cli->current_option; + state->is_short = cli->is_short; + state->whole_negated = cli->whole_negated; + state->current_short = cli->current_short; + state->negated_by_no = cli->negated_by_no; +} + + +/** @param clp the parser + * @param state parser state + * + * The parser state in @a state is restored into @a clp. The next call to + * Clp_Next() will return the same result as it would have at the time @a + * state was saved (probably by Clp_SaveParser(@a clp, @a state)). + * + * A parser state contains information about arguments (argc and argv; see + * Clp_SetArguments()) and option processing (Clp_SetOptionProcessing()), but + * not about options (Clp_SetOptions()). Changes to options and value types + * are preserved across Clp_RestoreParser(). + * + * @sa Clp_NewParserState, Clp_SaveParser + */ +void +Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state) +{ + Clp_Internal *cli = clp->internal; + cli->argv = state->argv; + cli->argc = state->argc; + memcpy(cli->option_chars, state->option_chars, Clp_OptionCharsSize); + cli->xtext = state->xtext; + cli->option_processing = state->option_processing; + cli->is_short = state->is_short; + cli->whole_negated = state->whole_negated; + cli->current_short = state->current_short; + cli->negated_by_no = state->negated_by_no; + if (cli->opt_generation == state->opt_generation) + cli->current_option = state->current_option; + else + cli->current_option = -1; +} + + +/******* + * Clp_Next and its helpers + **/ + +static void +set_option_text(Clp_Internal *cli, const char *text, int n_option_chars) +{ + assert(n_option_chars < Clp_OptionCharsSize); + memcpy(cli->option_chars, text, n_option_chars); + cli->option_chars[n_option_chars] = 0; + cli->xtext = text + n_option_chars; +} + +static int +get_oclass(Clp_Parser *clp, const char *text, int *ocharskip) +{ + int c; + if (clp->internal->utf8) { + const char *s; + c = decode_utf8(text, &s); + *ocharskip = s - text; + } else { + c = (unsigned char) text[0]; + *ocharskip = 1; + } + return Clp_OptionChar(clp, c); +} + +static int +next_argument(Clp_Parser *clp, int want_argument) + /* Moves clp to the next argument. + Returns 1 if it finds another option. + Returns 0 if there aren't any more arguments. + Returns 0, sets clp->have_val = 1, and sets clp->vstr to the argument + if the next argument isn't an option. + If want_argument > 0, it'll look for an argument. + want_argument == 1: Accept arguments that start with Clp_NotOption + or Clp_LongImplicit. + want_argument == 2: Accept ALL arguments. + + Where is the option stored when this returns? + Well, cli->argv[0] holds the whole of the next command line argument. + cli->option_chars holds a string: what characters began the option? + It is generally "-" or "--". + cli->text holds the text of the option: + for short options, cli->text[0] is the relevant character; + for long options, cli->text holds the rest of the option. */ +{ + Clp_Internal *cli = clp->internal; + const char *text; + int oclass, ocharskip; + + /* clear relevant flags */ + clp->have_val = 0; + clp->vstr = 0; + cli->could_be_short = 0; + + /* if we're in a string of short options, move up one char in the string */ + if (cli->is_short) { + cli->xtext += clp_utf8_charlen(cli, cli->xtext); + if (cli->xtext[0] == 0) + cli->is_short = 0; + else if (want_argument > 0) { + /* handle -O[=]argument case */ + clp->have_val = 1; + if (cli->xtext[0] == '=') + clp->vstr = cli->xtext + 1; + else + clp->vstr = cli->xtext; + cli->is_short = 0; + return 0; + } + } + + /* if in short options, we're all set */ + if (cli->is_short) + return 1; + + /** if not in short options, move to the next argument **/ + cli->whole_negated = 0; + cli->xtext = 0; + + if (cli->argc <= 1) + return 0; + + cli->argc--; + cli->argv++; + text = cli->argv[0]; + + if (want_argument > 1) + goto not_option; + + if (text[0] == '-' && text[1] == '-') { + oclass = Clp_DoubledLong; + ocharskip = 2; + } else + oclass = get_oclass(clp, text, &ocharskip); + + /* If this character could introduce either a short or a long option, + try a long option first, but remember that short's a possibility for + later. */ + if ((oclass & (Clp_Short | Clp_ShortNegated)) + && (oclass & (Clp_Long | Clp_LongNegated))) { + oclass &= ~(Clp_Short | Clp_ShortNegated); + if (text[ocharskip]) + cli->could_be_short = 1; + } + + switch (oclass) { + + case Clp_Short: + cli->is_short = 1; + goto check_singleton; + + case Clp_ShortNegated: + cli->is_short = 1; + cli->whole_negated = 1; + goto check_singleton; + + case Clp_Long: + goto check_singleton; + + case Clp_LongNegated: + cli->whole_negated = 1; + goto check_singleton; + + check_singleton: + /* For options introduced with one character, option-char, + '[option-char]' alone is NOT an option. */ + if (!text[ocharskip]) + goto not_option; + set_option_text(cli, text, ocharskip); + break; + + case Clp_LongImplicit: + /* LongImplict: option_chars == "" (since all chars are part of the + option); restore head -> text of option */ + if (want_argument > 0) + goto not_option; + set_option_text(cli, text, 0); + break; + + case Clp_DoubledLong: + set_option_text(cli, text, ocharskip); + break; + + not_option: + case Clp_NotOption: + cli->is_short = 0; + clp->have_val = 1; + clp->vstr = text; + return 0; + + default: + assert(0 /* CLP misconfiguration: bad option type */); + + } + + return 1; +} + + +static void +switch_to_short_argument(Clp_Parser *clp) +{ + Clp_Internal *cli = clp->internal; + const char *text = cli->argv[0]; + int ocharskip, oclass = get_oclass(clp, text, &ocharskip); + assert(cli->could_be_short); + cli->is_short = 1; + cli->whole_negated = (oclass & Clp_ShortNegated ? 1 : 0); + set_option_text(cli, cli->argv[0], ocharskip); +} + + +static int +find_long(Clp_Parser *clp, const char *arg) + /* If arg corresponds to one of clp's options, finds that option & + returns it. If any argument is given after an = sign in arg, sets + clp->have_val = 1 and clp->vstr to that argument. Sets cli->ambiguous + to 1 iff there was no match because the argument was ambiguous. */ +{ + Clp_Internal *cli = clp->internal; + int optno, len, lmm; + const Clp_Option *opt = cli->opt; + const Clp_InternOption *iopt; + int first_negative_ambiguous; + + /* Look for a normal option. */ + optno = find_prefix_opt + (clp, arg, cli->nopt, opt, cli->iopt, + &cli->ambiguous, cli->ambiguous_values); + if (optno >= 0) + goto worked; + + /* If we can't find it, look for a negated option. */ + /* I know this is silly, but it makes me happy to accept + --no-no-option as a double negative synonym for --option. :) */ + first_negative_ambiguous = cli->ambiguous; + while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') { + arg += 3; + clp->negated = !clp->negated; + optno = find_prefix_opt + (clp, arg, cli->nopt, opt, cli->iopt, + &cli->ambiguous, cli->ambiguous_values); + if (optno >= 0) + goto worked; + } + + /* No valid option was found; return 0. Mark the ambiguous values found + through '--no' by making them negative. */ + { + int i, max = cli->ambiguous; + if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES; + for (i = first_negative_ambiguous; i < max; i++) + cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1; + } + return -1; + + worked: + iopt = &cli->iopt[optno]; + lmm = (clp->negated ? iopt->lmmneg : iopt->lmmpos); + if (cli->could_be_short + && (clp->negated ? iopt->lmmneg_short : iopt->lmmpos_short)) { + int first_charlen = clp_utf8_charlen(cli, arg); + lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); + } + len = argcmp(opt[optno].long_name + iopt->ilongoff, arg, lmm, 1); + assert(len > 0); + if (arg[len] == '=') { + clp->have_val = 1; + clp->vstr = arg + len + 1; + } + return optno; +} + + +static int +find_short(Clp_Parser *clp, const char *text) + /* If short_name corresponds to one of clp's options, returns it. */ +{ + Clp_Internal *cli = clp->internal; + const Clp_Option *opt = cli->opt; + const Clp_InternOption *iopt = cli->iopt; + int i, c; + if (clp->internal->utf8) + c = decode_utf8(text, 0); + else + c = (unsigned char) *text; + + for (i = 0; i < cli->nopt; i++) + if (iopt[i].ishort && opt[i].short_name == c + && (clp->negated ? iopt[i].ineg : iopt[i].ipos)) + return i; + + return -1; +} + + +/** @param clp the parser + * @return option ID of next option + * + * Parse the next argument from the argument list, store information about + * that argument in the fields of @a clp, and return the option's ID. + * + * If an argument was successfully parsed, that option's ID is returned. + * Other possible return values are: + * + * <dl> + * <dt>Clp_Done</dt> + * <dd>There are no more arguments.</dd> + * <dt>Clp_NotOption</dt> + * <dd>The next argument was not an option. The argument's text is @a + * clp->vstr (and @a clp->val.s).</dd> + * <dt>Clp_BadOption</dt> + * <dd>The next argument was a bad option: either an option that wasn't + * understood, or an option lacking a required value, or an option whose value + * couldn't be parsed. The option has been skipped.</dd> + * <dt>Clp_Error</dt> + * <dd>There was an internal error. This should never occur unless a user + * messes with, for example, a Clp_Option array.</dd> + * </dl> + * + * The fields of @a clp are set as follows. + * + * <dl> + * <dt><tt>negated</tt></dt> + * <dd>1 if the option was negated, 0 if it wasn't.</dd> + * <dt><tt>have_val</tt></dt> + * <dd>1 if the option had a value, 0 if it didn't. Note that negated options + * are not allowed to have values.</dd> + * <dt><tt>vstr</tt></dt> + * <dd>The value string, if any. NULL if there was no value.</dd> + * <dt><tt>val</tt></dt> + * <dd>An option's value type will parse the value string into this + * union.</dd> + * </dl> + * + * The parsed argument is shifted off the argument list, so that sequential + * calls to Clp_Next() step through the arugment list. + */ +int +Clp_Next(Clp_Parser *clp) +{ + Clp_Internal *cli = clp->internal; + int optno; + const Clp_Option *opt; + Clp_ParserState clpsave; + int vtpos, complain; + + /* Set up clp */ + cli->current_option = -1; + cli->ambiguous = 0; + + /* Get the next argument or option */ + if (!next_argument(clp, cli->option_processing ? 0 : 2)) { + clp->val.s = clp->vstr; + clp->opt = clp->have_val ? Clp_NotOption : Clp_Done; + return clp->opt; + } + + clp->negated = cli->whole_negated; + if (cli->is_short) + optno = find_short(clp, cli->xtext); + else + optno = find_long(clp, cli->xtext); + + /* If there's ambiguity between long & short options, and we couldn't + find a long option, look for a short option */ + if (optno < 0 && cli->could_be_short) { + switch_to_short_argument(clp); + optno = find_short(clp, cli->xtext); + } + + /* If we didn't find an option... */ + if (optno < 0 || (clp->negated && !cli->iopt[optno].ineg)) { + /* default processing for the "--" option: turn off option processing + and return the next argument */ + if (strcmp(cli->argv[0], "--") == 0) { + Clp_SetOptionProcessing(clp, 0); + return Clp_Next(clp); + } + + /* otherwise, report some error or other */ + if (cli->ambiguous) + ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values, + cli->opt, cli->iopt, cli->option_chars, + "option %<%s%s%> is ambiguous", + cli->option_chars, cli->xtext); + else if (cli->is_short && !cli->could_be_short) + Clp_OptionError(clp, "unrecognized option %<%s%C%>", + cli->option_chars, cli->xtext); + else + Clp_OptionError(clp, "unrecognized option %<%s%s%>", + cli->option_chars, cli->xtext); + + return (clp->opt = Clp_BadOption); + } + + /* Set the current option */ + cli->current_option = optno; + cli->current_short = cli->is_short; + cli->negated_by_no = clp->negated && !cli->whole_negated; + + /* The no-argument (or should-have-no-argument) case */ + if (clp->negated + || (!cli->iopt[optno].imandatory && !cli->iopt[optno].ioptional)) { + if (clp->have_val) { + Clp_OptionError(clp, "%<%O%> can%,t take an argument"); + clp->opt = Clp_BadOption; + } else + clp->opt = cli->opt[optno].option_id; + return clp->opt; + } + + /* Get an argument if we need one, or if it's optional */ + /* Sanity-check the argument type. */ + opt = &cli->opt[optno]; + if (opt->val_type <= 0) + return (clp->opt = Clp_Error); + vtpos = val_type_binsearch(cli, opt->val_type); + if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != opt->val_type) + return (clp->opt = Clp_Error); + + /* complain == 1 only if the argument was explicitly given, + or it is mandatory. */ + complain = (clp->have_val != 0) || cli->iopt[optno].imandatory; + Clp_SaveParser(clp, &clpsave); + + if (cli->iopt[optno].imandatory && !clp->have_val) { + /* Mandatory argument case */ + /* Allow arguments to options to start with a dash, but only if the + argument type allows it by not setting Clp_DisallowOptions */ + int disallow = (cli->valtype[vtpos].flags & Clp_DisallowOptions) != 0; + next_argument(clp, disallow ? 1 : 2); + if (!clp->have_val) { + int got_option = cli->xtext != 0; + Clp_RestoreParser(clp, &clpsave); + if (got_option) + Clp_OptionError(clp, "%<%O%> requires a non-option argument"); + else + Clp_OptionError(clp, "%<%O%> requires an argument"); + return (clp->opt = Clp_BadOption); + } + + } else if (cli->is_short && !clp->have_val + && cli->xtext[clp_utf8_charlen(cli, cli->xtext)]) { + /* The -[option]argument case: + Assume that the rest of the current string is the argument. */ + next_argument(clp, 1); + complain = 1; + } + + /* Parse the argument */ + if (clp->have_val) { + Clp_ValType *atr = &cli->valtype[vtpos]; + if (atr->func(clp, clp->vstr, complain, atr->user_data) <= 0) { + /* parser failed */ + clp->have_val = 0; + if (complain) + return (clp->opt = Clp_BadOption); + else + Clp_RestoreParser(clp, &clpsave); + } + } + + return (clp->opt = opt->option_id); +} + + +/** @param clp the parser + * @param allow_options whether options will be allowed + * + * Remove and return the next argument from @a clp's argument array. If there + * are no arguments left, or if the next argument is an option and @a + * allow_options != 0, then returns null. + */ +const char * +Clp_Shift(Clp_Parser *clp, int allow_options) + /* Returns the next argument from the argument list without parsing it. + If there are no more arguments, returns 0. */ +{ + Clp_ParserState clpsave; + Clp_SaveParser(clp, &clpsave); + next_argument(clp, allow_options ? 2 : 1); + if (!clp->have_val) + Clp_RestoreParser(clp, &clpsave); + return clp->vstr; +} + + +/******* + * Clp_OptionError + **/ + +typedef struct Clp_BuildString { + char *text; + char *pos; + int capacity; + int bad; +} Clp_BuildString; + +static Clp_BuildString * +new_build_string(void) +{ + Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString)); + if (!bs) goto bad; + bs->text = (char *)malloc(256); + if (!bs->text) goto bad; + bs->pos = bs->text; + bs->capacity = 256; + bs->bad = 0; + return bs; + + bad: + if (bs) free(bs); + return 0; +} + +static void +free_build_string(Clp_BuildString *bs) +{ + if (bs) free(bs->text); + free(bs); +} + +static int +grow_build_string(Clp_BuildString *bs, int want) +{ + char *new_text; + int ipos = bs->pos - bs->text; + int new_capacity = bs->capacity; + while (want >= new_capacity) + new_capacity *= 2; + new_text = (char *)realloc(bs->text, new_capacity); + if (!new_text) { + bs->bad = 1; + return 0; + } else { + bs->text = new_text; + bs->pos = bs->text + ipos; + bs->capacity = new_capacity; + return 1; + } +} + +#define ENSURE_BUILD_STRING(bs, space) \ + ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity) \ + || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space))) + +static void +append_build_string(Clp_BuildString *bs, const char *s, int l) +{ + if (l < 0) + l = strlen(s); + if (ENSURE_BUILD_STRING(bs, l)) { + memcpy(bs->pos, s, l); + bs->pos += l; + } +} + + +static Clp_BuildString * +Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs, + const char *fmt, va_list val) +{ + Clp_Internal *cli = clp->internal; + const char *percent; + int c; + + if (!bs) + bs = new_build_string(); + if (!bs) + return 0; + if (cli->program_name && cli->program_name[0]) { + append_build_string(bs, cli->program_name, -1); + append_build_string(bs, ": ", 2); + } + + for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) { + append_build_string(bs, fmt, percent - fmt); + switch (*++percent) { + + case 's': { + const char *s = va_arg(val, const char *); + if (s) + append_build_string(bs, s, -1); + else + append_build_string(bs, "(null)", 6); + break; + } + + case 'C': { + const char *s = va_arg(val, const char *); + if (cli->utf8) + c = decode_utf8(s, 0); + else + c = (unsigned char) *s; + goto char_c; + } + + case 'c': + c = va_arg(val, int); + goto char_c; + + char_c: + if (ENSURE_BUILD_STRING(bs, 4)) { + if (c >= 32 && c <= 126) + *bs->pos++ = c; + else if (c < 32) { + *bs->pos++ = '^'; + *bs->pos++ = c + 64; + } else if (cli->utf8 && c >= 127 && c < 0x110000) { + bs->pos = encode_utf8(bs->pos, 4, c); + } else if (c >= 127 && c <= 255) { + sprintf(bs->pos, "\\%03o", c & 0xFF); + bs->pos += 4; + } else { + *bs->pos++ = '\\'; + *bs->pos++ = '?'; + } + } + break; + + case 'd': { + int d = va_arg(val, int); + if (ENSURE_BUILD_STRING(bs, 32)) { + sprintf(bs->pos, "%d", d); + bs->pos = strchr(bs->pos, 0); + } + break; + } + + case 'O': { + int optno = cli->current_option; + const Clp_Option *opt = &cli->opt[optno]; + if (optno < 0) + append_build_string(bs, "(no current option!)", -1); + else if (cli->current_short) { + append_build_string(bs, cli->option_chars, -1); + if (ENSURE_BUILD_STRING(bs, 5)) { + if (cli->utf8) + bs->pos = encode_utf8(bs->pos, 5, opt->short_name); + else + *bs->pos++ = opt->short_name; + } + } else if (cli->negated_by_no) { + append_build_string(bs, cli->option_chars, -1); + append_build_string(bs, "no-", 3); + append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); + } else { + append_build_string(bs, cli->option_chars, -1); + append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); + } + break; + } + + case '%': + if (ENSURE_BUILD_STRING(bs, 1)) + *bs->pos++ = '%'; + break; + + case '`': /* backwards compatibility */ + case '<': + append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); + break; + + case '\'': /* backwards compatibility */ + case ',': + case '>': + append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); + break; + + default: + if (ENSURE_BUILD_STRING(bs, 2)) { + *bs->pos++ = '%'; + *bs->pos++ = *percent; + } + break; + + } + fmt = ++percent; + } + + append_build_string(bs, fmt, -1); + append_build_string(bs, "\n", 1); + + return bs; +} + +static void +do_error(Clp_Parser *clp, Clp_BuildString *bs) +{ + const char *text; + if (bs && !bs->bad) { + *bs->pos = 0; + text = bs->text; + } else + text = "out of memory\n"; + + if (clp->internal->error_handler != 0) + (*clp->internal->error_handler)(clp, text); + else + fputs(text, stderr); +} + +/** @param clp the parser + * @param format error format + * + * Format an error message from @a format and any additional arguments in the + * ellipsis. The resulting error string by printing it to standard error or + * passing it to Clp_SetErrorHandler. + * + * The following format characters are accepted: + * + * <dl> + * <dt><tt>%</tt><tt>c</tt></dt> + * <dd>A character (type <tt>int</tt>). Control characters are printed in + * caret notation. If the parser is in UTF-8 mode, the character is formatted + * in UTF-8. Otherwise, special characters are printed with backslashes and + * octal notation.</dd> + * <dt><tt>%</tt><tt>s</tt></dt> + * <dd>A string (type <tt>const char *</tt>).</dd> + * <dt><tt>%</tt><tt>C</tt></dt> + * <dd>The argument is a string (type <tt>const char *</tt>). The first + * character in this string is printed. If the parser is in UTF-8 mode, this + * may involve multiple bytes.</dd> + * <dt><tt>%</tt><tt>d</tt></dt> + * <dd>An integer (type <tt>int</tt>). Printed in decimal.</dd> + * <dt><tt>%</tt><tt>O</tt></dt> + * <dd>The current option. No values are read from the argument list; the + * current option is defined in the Clp_Parser object itself.</dd> + * <dt><tt>%%</tt></dt> + * <dd>Prints a percent character.</dd> + * <dt><tt>%</tt><tt><</tt></dt> + * <dd>Prints an open quote string. In UTF-8 mode, prints a left single + * quote. Otherwise prints a single quote.</dd> + * <dt><tt>%</tt><tt>></tt></dt> + * <dd>Prints a closing quote string. In UTF-8 mode, prints a right single + * quote. Otherwise prints a single quote.</dd> + * <dt><tt>%</tt><tt>,</tt></dt> + * <dd>Prints an apostrophe. In UTF-8 mode, prints a right single quote. + * Otherwise prints a single quote.</dd> + * </dl> + * + * Note that no flag characters, precision, or field width characters are + * currently supported. + * + * @sa Clp_SetErrorHandler + */ +int +Clp_OptionError(Clp_Parser *clp, const char *format, ...) +{ + Clp_BuildString *bs; + va_list val; + va_start(val, format); + bs = Clp_VaOptionError(clp, 0, format, val); + va_end(val); + do_error(clp, bs); + free_build_string(bs); + return 0; +} + +static int +ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values, + const Clp_Option *opt, const Clp_InternOption *iopt, + const char *prefix, const char *fmt, ...) +{ + Clp_Internal *cli = clp->internal; + Clp_BuildString *bs; + int i; + va_list val; + va_start(val, fmt); + bs = Clp_VaOptionError(clp, 0, fmt, val); + if (!bs) goto done; + + if (clp->internal->program_name && clp->internal->program_name[0]) { + append_build_string(bs, clp->internal->program_name, -1); + append_build_string(bs, ": ", 2); + } + append_build_string(bs, "(Possibilities are", -1); + + for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) { + int value = ambiguous_values[i]; + const char *no_dash = ""; + if (value < 0) + value = -(value + 1), no_dash = "no-"; + if (i == 0) + append_build_string(bs, " ", 1); + else if (i == ambiguous - 1) + append_build_string(bs, (i == 1 ? " and " : ", and "), -1); + else + append_build_string(bs, ", ", 2); + append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); + append_build_string(bs, prefix, -1); + append_build_string(bs, no_dash, -1); + append_build_string(bs, opt[value].long_name + iopt[value].ilongoff, -1); + append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); + } + + if (ambiguous > MAX_AMBIGUOUS_VALUES) + append_build_string(bs, ", and others", -1); + append_build_string(bs, ".)\n", -1); + va_end(val); + + done: + do_error(clp, bs); + free_build_string(bs); + return 0; +} + +static int +copy_string(char *buf, int buflen, int bufpos, const char *what) +{ + int l = strlen(what); + if (l > buflen - bufpos - 1) + l = buflen - bufpos - 1; + memcpy(buf + bufpos, what, l); + return l; +} + +/** @param clp the parser + * @param buf output buffer + * @param len length of output buffer + * @return number of characters written to the buffer, not including the terminating NUL + * + * A string that looks like the last option parsed by @a clp is extracted into + * @a buf. The correct option characters are put into the string first, + * followed by the option text. The output buffer is null-terminated unless + * @a len == 0. + * + * @sa Clp_CurOptionName + */ +int +Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len) +{ + Clp_Internal *cli = clp->internal; + int optno = cli->current_option; + int pos = 0; + if (optno < 0) + pos += copy_string(buf, len, pos, "(no current option!)"); + else if (cli->current_short) { + pos += copy_string(buf, len, pos, cli->option_chars); + if (cli->utf8) + pos = (encode_utf8(buf + pos, len - pos - 1, cli->opt[optno].short_name) - buf); + else if (pos < len - 1) + buf[pos++] = cli->opt[optno].short_name; + } else if (cli->negated_by_no) { + pos += copy_string(buf, len, pos, cli->option_chars); + pos += copy_string(buf, len, pos, "no-"); + pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); + } else { + pos += copy_string(buf, len, pos, cli->option_chars); + pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); + } + if (pos < len) + buf[pos] = 0; + return pos; +} + +/** @param clp the parser + * @return string describing the current option + * + * This function acts like Clp_CurOptionNameBuf(), but returns a pointer into + * a static buffer that will be rewritten on the next call to + * Clp_CurOptionName(). + * + * @note This function is not thread safe. + * + * @sa Clp_CurOptionName + */ +const char * +Clp_CurOptionName(Clp_Parser *clp) +{ + static char buf[256]; + Clp_CurOptionNameBuf(clp, buf, 256); + return buf; +} + +#ifdef __cplusplus +} +#endif diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc new file mode 100644 index 00000000000..cfef2f07de9 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc @@ -0,0 +1,1169 @@ +// -*- related-file-name: "../include/lcdf/error.hh" -*- +/* + * error.{cc,hh} -- flexible classes for error reporting + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * Copyright (c) 2001-2013 Eddie Kohler + * Copyright (c) 2008 Meraki, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/error.hh> +#include <lcdf/straccum.hh> +#include <lcdf/hashmap.hh> +#include <errno.h> +#include <ctype.h> +#include <algorithm> +#ifndef __KERNEL__ +# include <stdlib.h> +# if HAVE_UNISTD_H +# include <unistd.h> +# endif +#endif + +/** @file error.hh + * @brief Flexible error handling classes. + */ + +struct ErrorHandler::Conversion { + String name; + ConversionFunction hook; + Conversion *next; +}; +static ErrorHandler::Conversion *error_items; + +const char ErrorHandler::e_abort[] = "<-999>"; +const char ErrorHandler::e_fatal[] = "<-1>"; +const char ErrorHandler::e_emergency[] = "<0>"; +const char ErrorHandler::e_alert[] = "<1>"; +const char ErrorHandler::e_critical[] = "<2>"; +const char ErrorHandler::e_error[] = "<3>"; +const char ErrorHandler::e_warning[] = "<4>"; +const char ErrorHandler::e_warning_annotated[] = "<4>warning: "; +const char ErrorHandler::e_notice[] = "<5>"; +const char ErrorHandler::e_info[] = "<6>"; +const char ErrorHandler::e_debug[] = "<7>"; + +const int ErrorHandler::ok_result = 0; +const int ErrorHandler::error_result = -EINVAL; + +ErrorHandler *ErrorHandler::the_default_handler = 0; +ErrorHandler *ErrorHandler::the_silent_handler = 0; + + +// ANNOTATION MANAGEMENT + +static const char * +parse_level(const char *begin, const char *end, int *result) +{ + int x = 0; + const char *s = begin; + + bool negative = false; + if (s != end && *s == '-') { + negative = true; + ++s; + } else if (s != end && *s == '+') + ++s; + + const char *digits = s; + for (; s != end && *s >= '0' && *s <= '9'; ++s) + x = x * 10 + *s - '0'; + + if (s != end && *s == '.') + for (++s; s != end && *s >= '0' && *s <= '9'; ++s) + /* nada */; + + if (s == digits || (s == digits + 1 && s[-1] == '.')) + return begin; + if (result) + *result = (negative ? -x : x); + return s; +} + +String +ErrorHandler::make_anno(const char *name, const String &value) +{ + StringAccum sa; + sa.reserve(value.length() + 10); + + // level annotation requires special handling + if (name[0] == '<' && name[1] == '>' && name[2] == 0) { + if (parse_level(value.begin(), value.end(), 0) == value.end()) { + sa << '<' << value << '>'; + return sa.take_string(); + } else + return String(); + } + + sa << '{' << name << ':'; + const char *last = value.begin(), *end = value.end(); + for (const char *s = value.begin(); s != end; ++s) + if (*s == '\\' || *s == '}') { + sa.append(last, s); + sa << '\\' << *s; + last = s + 1; + } else if (*s == '\n') { + sa.append(last, s); + sa << '\\' << 'n'; + last = s + 1; + } + sa.append(last, end); + sa << '}'; + return sa.take_string(); +} + +const char * +ErrorHandler::skip_anno(const String &str, const char *begin, const char *end, + String *name_result, String *value_result, bool raw) +{ + String name, value; + const char *s = begin; + + if (s + 3 <= end && *s == '<') { + const char *x = parse_level(s + 1, end, 0); + if (x != s + 1 && x != end && *x == '>') { + name = String::make_stable("<>", 2); + if (str) + value = str.substring(begin + 1, x); + begin = x + 1; + } + + } else if (s + 2 <= end && *s == '{' && s[1] == '}') + begin = s + 2; + + else if (s + 3 <= end && *s == '{' && str) { + for (++s; s != end && isalnum((unsigned char) *s); ++s) + /* nada */; + if (s == end || s == begin + 1 || (*s != '}' && *s != ':')) + /* not an annotation */; + else if (*s == '}' && str) { + name = str.substring(begin + 1, s); + begin = s + 1; + } else if (*s == '}') { + name = String::make_stable("{}", 2); + begin = s + 1; + } else if (str) { + const char *x, *last = s + 1; + StringAccum sa; + for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x) + if (*x == '\\' && x + 1 != end && x[1] != '\n') { + if (!raw) { + sa.append(last, x); + sa << (x[1] == 'n' ? '\n' : x[1]); + last = x + 2; + } + ++x; + } + if (x != end && *x == '}') { + name = str.substring(begin + 1, s); + if (sa) { + sa.append(last, x); + value = sa.take_string(); + } else + value = str.substring(s + 1, x); + begin = x + 1; + } + } else { + const char *x; + for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x) + if (*x == '\\' && x + 1 != end && x[1] != '\n') + ++x; + if (x != end && *x == '}') { + name = String::make_stable("{}", 2); + begin = x + 1; + } + } + } + + if (name_result) + *name_result = name; + if (value_result) + *value_result = value; + return begin; +} + +const char * +ErrorHandler::parse_anno(const String &str, const char *begin, const char *end, + ...) +{ + const char *names[8]; + void *values[8]; + int nanno = 0; + + va_list val; + va_start(val, end); + while (const char *n = va_arg(val, const char *)) { + assert(nanno < 8); + names[nanno] = n; + if (n[0] == '#') + values[nanno] = va_arg(val, int *); + else + values[nanno] = va_arg(val, String *); + ++nanno; + } + + String name, value; + while (1) { + begin = skip_anno(str, begin, end, &name, &value, false); + if (!name) + break; + for (int i = 0; i < nanno; ++i) + if (names[i][0] == '#') { + if (name == (names[i] + 1)) + parse_level(value.begin(), value.end(), (int *) values[i]); + } else { + if (name == names[i]) + *(String *) values[i] = value; + } + } + + return begin; +} + +String +ErrorHandler::combine_anno(const String &text, const String &anno) +{ + if (!anno) + return text; + + String names[8], values[8]; + int nanno = 0; + const char *abegin = anno.begin(); + while (abegin != anno.end()) { + assert(nanno < 8); + abegin = skip_anno(anno, abegin, anno.end(), &names[nanno], &values[nanno], true); + if (names[nanno]) + ++nanno; + else + break; + } + + const char *last = text.begin(), *s = last; + String name; + StringAccum sa; + while (s != text.end()) { + const char *line = s; + uint32_t mask = (1U << nanno) - 1; + while (1) { + s = skip_anno(text, s, text.end(), &name, 0, false); + if (!name) + break; + for (int i = 0; i < nanno; ++i) + if (name == names[i]) + mask &= ~(1U << i); + } + + if (mask) { + sa.append(last, line); + for (int i = 0; i < nanno; ++i) + if (mask & (1U << i)) { + if (names[i].equals("<>", 2)) + sa << '<' << values[i] << '>'; + else + sa << '{' << names[i] << ':' << values[i] << '}'; + } + last = line; + } + if (abegin != anno.end()) { + sa.append(last, s); + sa.append(abegin, anno.end()); + last = s; + } + + while (s != text.end() && *s != '\n') + ++s; + if (s != text.end()) + ++s; + } + + if (sa) { + sa.append(last, text.end()); + return sa.take_string(); + } else + return text; +} + +String +ErrorHandler::clean_landmark(const String &landmark, bool with_colon) +{ + const char *end = landmark.end(); + while (end != landmark.begin() && isspace((unsigned char) end[-1])) + --end; + if (end != landmark.begin() && end[-1] == ':') + --end; + if (end == landmark.begin()) + return String(); + else if (with_colon) + return landmark.substring(landmark.begin(), end) + ": "; + else + return landmark.substring(landmark.begin(), end); +} + + +// FORMATTING + +#define NUMBUF_SIZE 128 +#define ErrH ErrorHandler + +static char * +do_number(unsigned long num, char *after_last, int base, int flags) +{ + const char *digits = + ((flags & ErrH::cf_uppercase) ? "0123456789ABCDEF" : "0123456789abcdef"); + char *pos = after_last; + while (num) { + *--pos = digits[num % base]; + num /= base; + } + if (pos == after_last) + *--pos = '0'; + return pos; +} + +static char * +do_number_flags(char *pos, char *after_last, int base, int flags, + int precision, int field_width) +{ + // remove cf_alternate_form for zero results in base 16 + if ((flags & ErrH::cf_alternate_form) && base == 16 && *pos == '0') + flags &= ~ErrH::cf_alternate_form; + + // account for zero padding + if (precision >= 0) + while (after_last - pos < precision) + *--pos = '0'; + else if (flags & ErrH::cf_zero_pad) { + if ((flags & ErrH::cf_alternate_form) && base == 16) + field_width -= 2; + if ((flags & ErrH::cf_negative) + || (flags & (ErrH::cf_plus_positive | ErrH::cf_space_positive))) + field_width--; + while (after_last - pos < field_width) + *--pos = '0'; + } + + // alternate forms + if ((flags & ErrH::cf_alternate_form) && base == 8 && pos[1] != '0') + *--pos = '0'; + else if ((flags & ErrH::cf_alternate_form) && base == 16) { + *--pos = ((flags & ErrH::cf_uppercase) ? 'X' : 'x'); + *--pos = '0'; + } + + // sign + if (flags & ErrH::cf_negative) + *--pos = '-'; + else if (flags & ErrH::cf_plus_positive) + *--pos = '+'; + else if (flags & ErrH::cf_space_positive) + *--pos = ' '; + + return pos; +} + +String +ErrorHandler::vxformat(int default_flags, const char *s, va_list val) +{ + StringAccum msg; + + char numbuf[NUMBUF_SIZE]; // for numerics + numbuf[NUMBUF_SIZE-1] = 0; + + String strstore; // to ensure temporaries aren't destroyed + + // declare and initialize these here to make gcc shut up about possible + // use before initialization + int flags = 0; + int field_width = -1; + int precision = -1; + int width_flag = 0; + int base = 10; + while (1) { + + const char *pct = strchr(s, '%'); + if (!pct) { + if (*s) + msg << s; + break; + } + if (pct != s) { + msg.append(s, pct - s); + s = pct; + } + + // parse flags + flags = default_flags; + flags: + switch (*++s) { + case '#': flags |= cf_alternate_form; goto flags; + case '0': flags |= cf_zero_pad; goto flags; + case '-': flags |= cf_left_just; goto flags; + case ' ': flags |= cf_space_positive; goto flags; + case '+': flags |= cf_plus_positive; goto flags; + case '\'': flags |= cf_singlequote; goto flags; + case '_': flags &= ~cf_utf8; goto flags; + } + + // parse field width + field_width = -1; + if (*s == '*') { + field_width = va_arg(val, int); + if (field_width < 0) { + field_width = -field_width; + flags |= cf_left_just; + } + s++; + } else if (*s >= '0' && *s <= '9') + for (field_width = 0; *s >= '0' && *s <= '9'; s++) + field_width = 10*field_width + *s - '0'; + + // parse precision + precision = -1; + if (*s == '.') { + s++; + precision = 0; + if (*s == '*') { + precision = va_arg(val, int); + s++; + } else if (*s >= '0' && *s <= '9') + for (; *s >= '0' && *s <= '9'; s++) + precision = 10*precision + *s - '0'; + } + + // parse width flags + width_flag = 0; + width_flags: + switch (*s) { + case 'h': case 'l': + if (width_flag == *s) + width_flag = *s + 'A' - 'a'; + else if (width_flag) + break; + else + width_flag = *s; + s++; + goto width_flags; + case 'z': + if (width_flag) + break; + width_flag = *s++; + break; + case '^': + if (!isdigit((unsigned char) s[1]) || width_flag) + break; + for (s++; isdigit((unsigned char) *s); s++) + width_flag = width_flag * 10 + *s - '0'; + width_flag = -width_flag; + break; + } + + // conversion character + // after switch, data lies between `s1' and `s2' + const char *s1 = 0, *s2 = 0; + base = 10; + switch (*s++) { + + case 's': { + s1 = va_arg(val, const char *); + if (!s1) + s1 = "(null)"; + + // fetch length + int len; + if (precision < 0) + len = strlen(s1); + else + len = strnlen(s1, precision); + + // transform string if alternate form + if (flags & cf_alternate_form) { + strstore = String(s1, len).printable(); + if (precision < 0 || strstore.length() < precision) + len = strstore.length(); + } + + // quote characters that look like annotations, readjusting length + if (flags & (cf_singlequote | cf_alternate_form)) { + if (!(flags & cf_alternate_form)) + strstore = String(s1, len); + + // check first line, considering trailing part of 'msg' + const char *mbegin = msg.end(); + while (mbegin != msg.begin() && mbegin[-1] != '\n') + --mbegin; + if (skip_anno(strstore.begin(), strstore.end()) != strstore.begin() + && skip_anno(mbegin, msg.end()) == msg.end()) { + strstore = String::make_stable("{}", 2) + strstore; + len += 2; + } + + // check subsequent lines + const char *s = std::find(strstore.begin(), strstore.end(), '\n'); + while (s != strstore.end() && s + 1 != strstore.end()) { + size_t nextpos = (s + 1) - strstore.begin(); + if (skip_anno(s + 1, strstore.end()) != s + 1) { + strstore = strstore.substring(strstore.begin(), s + 1) + + String::make_stable("{}", 2) + + strstore.substring(s + 1, strstore.end()); + len += 2; + } + s = std::find(strstore.begin() + nextpos, strstore.end(), '\n'); + } + } + + // obtain begin and end pointers + if (flags & (cf_singlequote | cf_alternate_form)) + s1 = strstore.begin(); + s2 = s1 + len; + break; + } + + case 'c': { + int c = va_arg(val, int); + // check for extension of 'signed char' to 'int' + if (c < 0) + c += 256; + // assume ASCII + if (c == '\n') + strcpy(numbuf, "\\n"); + else if (c == '\t') + strcpy(numbuf, "\\t"); + else if (c == '\r') + strcpy(numbuf, "\\r"); + else if (c == '\0') + strcpy(numbuf, "\\0"); + else if (c < 0 || c >= 256) + strcpy(numbuf, "(bad char)"); + else if (c < 32 || c >= 0177) + sprintf(numbuf, "\\%03o", c); + else + sprintf(numbuf, "%c", c); + s1 = numbuf; + s2 = strchr(numbuf, 0); + break; + } + + case '%': { + numbuf[0] = '%'; + s1 = numbuf; + s2 = s1 + 1; + break; + } + + case '<': + s1 = (flags & cf_utf8 ? "\342\200\230" : "\'"); + s2 = s1 + strlen(s1); + break; + + case '>': + case ',': + s1 = (flags & cf_utf8 ? "\342\200\231" : "\'"); + s2 = s1 + strlen(s1); + break; + + case 'd': + case 'i': + flags |= cf_signed; + case 'u': + number: { + // protect numbuf from overflow + if (field_width > NUMBUF_SIZE) + field_width = NUMBUF_SIZE; + if (precision > NUMBUF_SIZE - 4) + precision = NUMBUF_SIZE - 4; + + s2 = numbuf + NUMBUF_SIZE; + + unsigned long num; + switch (width_flag) { + case 'H': + case -8: + num = (unsigned char) va_arg(val, int); + if ((flags & cf_signed) && (signed char) num < 0) + num = -(signed char) num, flags |= cf_negative; + break; + case 'h': + case -16: + num = (unsigned short) va_arg(val, int); + if ((flags & cf_signed) && (short) num < 0) + num = -(short) num, flags |= cf_negative; + break; + case 0: + case -32: +#if SIZEOF_LONG == 4 + case 'l': +#endif +#if SIZEOF_SIZE_T == 4 + case 'z': +#endif + num = va_arg(val, unsigned); + if ((flags & cf_signed) && (int) num < 0) + num = -(int) num, flags |= cf_negative; + break; +#if HAVE_INT64_TYPES +# if SIZEOF_LONG == 8 + case 'l': +# endif +# if SIZEOF_LONG_LONG == 8 + case 'L': +# endif +# if SIZEOF_SIZE_T == 8 + case 'z': +# endif + case -64: { + uint64_t qnum = va_arg(val, uint64_t); + if ((flags & cf_signed) && (int64_t)qnum < 0) + qnum = -(int64_t) qnum, flags |= cf_negative; + StringAccum sa; + sa.append_numeric(static_cast<String::uintmax_t>(qnum), base, (flags & cf_uppercase)); + s1 = s2 - sa.length(); + memcpy(const_cast<char*>(s1), sa.data(), s2 - s1); + goto got_number; + } +#endif + default: + goto error; + } + s1 = do_number(num, (char *)s2, base, flags); + +#if HAVE_INT64_TYPES + got_number: +#endif + s1 = do_number_flags((char *)s1, (char *)s2, base, flags, + precision, field_width); + break; + } + + case 'o': + base = 8; + goto number; + + case 'X': + flags |= cf_uppercase; + case 'x': + base = 16; + goto number; + + case 'p': { + if (*s == '{') { + s1 = s2 = s + 1; + while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2)) + ++s2; + if (*s2 == '}') + goto braces; + } + void *v = va_arg(val, void *); + s2 = numbuf + NUMBUF_SIZE; + s1 = do_number((unsigned long)v, (char *)s2, 16, flags); + s1 = do_number_flags((char *)s1, (char *)s2, 16, flags | cf_alternate_form, + precision, field_width); + break; + } + +#ifndef __KERNEL__ + case 'e': case 'f': case 'g': + case 'E': case 'F': case 'G': { + char format[80], *f = format, new_numbuf[NUMBUF_SIZE]; + *f++ = '%'; + if (flags & cf_alternate_form) + *f++ = '#'; + if (precision >= 0) + f += sprintf(f, ".%d", precision); + *f++ = s[-1]; + *f++ = 0; + + int len = sprintf(new_numbuf, format, va_arg(val, double)); + + s2 = numbuf + NUMBUF_SIZE; + s1 = s2 - len; + memcpy((char *)s1, new_numbuf, len); // note: no terminating \0 + s1 = do_number_flags((char *)s1, (char *)s2, 10, flags & ~cf_alternate_form, -1, field_width); + break; + } +#endif + + case '{': + s1 = s2 = s; + while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2)) + ++s2; + if (*s2 != '}') + goto error; + goto braces; + + braces: + s = s2 + 1; + for (Conversion *item = error_items; item; item = item->next) + if (item->name.equals(s1, s2 - s1)) { + strstore = item->hook(flags, VA_LIST_REF(val)); + s1 = strstore.begin(); + s2 = strstore.end(); + goto got_result; + } + goto error; + + error: + default: + assert(0 /* Bad % in error */); + break; + + } + + // add result of conversion + got_result: + int slen = s2 - s1; + if (slen > field_width) + field_width = slen; + char *dest = msg.extend(field_width); + if (flags & cf_left_just) { + memcpy(dest, s1, slen); + memset(dest + slen, ' ', field_width - slen); + } else { + memcpy(dest + field_width - slen, s1, slen); + memset(dest, (flags & cf_zero_pad ? '0' : ' '), field_width - slen); + } + } + + return msg.take_string(); +} + +String +ErrorHandler::xformat(int default_flags, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vxformat(default_flags, fmt, val); + va_end(val); + return s; +} + +String +ErrorHandler::xformat(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vxformat(0, fmt, val); + va_end(val); + return s; +} + +String +ErrorHandler::format(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vformat(fmt, val); + va_end(val); + return s; +} + + +// ERROR MESSAGE SHORTHAND + +void +ErrorHandler::debug(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + vxmessage(String::make_stable(e_debug, 3), fmt, val); + va_end(val); +} + +void +ErrorHandler::message(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + vxmessage(String::make_stable(e_info, 3), fmt, val); + va_end(val); +} + +int +ErrorHandler::warning(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_warning_annotated, 12), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::error(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_error, 3), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::fatal(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_fatal, 4), fmt, val); + va_end(val); + return r; +} + +void +ErrorHandler::ldebug(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + vxmessage(String::make_stable(e_debug, 3) + l, fmt, val); + va_end(val); +} + +void +ErrorHandler::lmessage(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + vxmessage(String::make_stable(e_info, 3) + l, fmt, val); + va_end(val); +} + +int +ErrorHandler::lwarning(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(l + String::make_stable(e_warning_annotated, 12), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::lerror(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(String::make_stable(e_error, 3) + l, fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::lfatal(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(String::make_stable(e_fatal, 4) + l, fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::xmessage(const String &str) +{ + String xstr = decorate(str); + + int min_level = 1000, xlevel = 1000; + const char *s = xstr.begin(), *end = xstr.end(); + void *user_data = 0; + while (s != end) { + const char *l = parse_anno(xstr, s, end, "#<>", &xlevel, + (const char *) 0); + const char *nl = std::find(l, end, '\n'); + String line = xstr.substring(s, nl); + s = nl + (nl != end); + user_data = emit(line, user_data, s != end); + min_level = (xlevel < min_level ? xlevel : min_level); + } + + account(min_level); + + return (min_level <= el_warning ? error_result : ok_result); +} + +String +ErrorHandler::vformat(const char *fmt, va_list val) +{ + return vxformat(0, fmt, val); +} + +String +ErrorHandler::decorate(const String &str) +{ + return str; +} + +void * +ErrorHandler::emit(const String &, void *user_data, bool) +{ + return user_data; +} + + +#ifndef __KERNEL__ +// +// FILE ERROR HANDLER +// + +FileErrorHandler::FileErrorHandler(FILE *f, const String &context) + : _f(f), _context(context), _default_flags(0) +{ +# if HAVE_UNISTD_H + if (isatty(fileno(_f))) { +# endif + char *s = getenv("LANG"); + if (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0 + || strstr(s, "utf8") != 0)) + _default_flags |= cf_utf8; +# if HAVE_UNISTD_H + } +# endif +} + +String +FileErrorHandler::vformat(const char *fmt, va_list val) +{ + return vxformat(_default_flags, fmt, val); +} + +void * +FileErrorHandler::emit(const String &str, void *, bool) +{ + String landmark; + const char *s = parse_anno(str, str.begin(), str.end(), + "l", &landmark, (const char *) 0); + StringAccum sa; + sa << _context << clean_landmark(landmark, true) + << str.substring(s, str.end()) << '\n'; + ssize_t result = fwrite(sa.begin(), 1, sa.length(), _f); + (void) result; + return 0; +} + +void +FileErrorHandler::account(int level) +{ + ErrorHandler::account(level); + if (level <= el_abort) + abort(); + else if (level <= el_fatal) + exit(-level); +} + +#endif + + +// +// STATIC ERROR HANDLERS +// + +ErrorHandler::Conversion * +ErrorHandler::add_conversion(const String &name, ConversionFunction function) +{ + if (Conversion *c = new Conversion) { + c->name = name; + c->hook = function; + c->next = error_items; + error_items = c; + return c; + } else + return 0; +} + +int +ErrorHandler::remove_conversion(ErrorHandler::Conversion *conv) +{ + Conversion **pprev = &error_items; + for (Conversion *c = error_items; c; pprev = &c->next, c = *pprev) + if (c == conv) { + *pprev = c->next; + delete c; + return 0; + } + return -1; +} + +ErrorHandler * +ErrorHandler::static_initialize(ErrorHandler *default_handler) +{ + if (!the_silent_handler) { + the_default_handler = default_handler; + the_silent_handler = new SilentErrorHandler; + } + return default_handler; +} + +void +ErrorHandler::static_cleanup() +{ + delete the_default_handler; + delete the_silent_handler; + the_default_handler = the_silent_handler = 0; + while (error_items) { + Conversion *next = error_items->next; + delete error_items; + error_items = next; + } +} + +void +ErrorHandler::set_default_handler(ErrorHandler *errh) +{ + the_default_handler = errh; +} + + +// +// ERROR VENEER +// + +String +ErrorVeneer::vformat(const char *fmt, va_list val) +{ + if (_errh) + return _errh->vformat(fmt, val); + else + return ErrorHandler::vformat(fmt, val); +} + +String +ErrorVeneer::decorate(const String &str) +{ + if (_errh) + return _errh->decorate(str); + else + return ErrorHandler::decorate(str); +} + +void * +ErrorVeneer::emit(const String &str, void *user_data, bool more) +{ + if (_errh) + return _errh->emit(str, user_data, more); + else + return ErrorHandler::emit(str, user_data, more); +} + +void +ErrorVeneer::account(int level) +{ + ErrorHandler::account(level); + if (_errh) + _errh->account(level); +} + + +// +// CONTEXT ERROR HANDLER +// + +ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt, + ...) + : ErrorVeneer(errh), _indent(String::make_stable(" ", 2)), + _context_printed(false) +{ + va_list val; + va_start(val, fmt); + _context = ErrorVeneer::vformat(fmt, val); + va_end(val); + if (_context) + _context = combine_anno(_context, String::make_stable("{context:context}", 17)); +} + +String +ContextErrorHandler::decorate(const String &str) +{ + String context_anno; + const char *str_endanno = parse_anno(str, str.begin(), str.end(), + "context", &context_anno, + (const char *) 0); + if (context_anno.equals("no", 2)) + return ErrorVeneer::decorate(str); + + String istr; + if (context_anno.equals("noindent", 8)) + istr = combine_anno(str, _context_landmark); + else + istr = combine_anno(str, _context_landmark + _indent); + + if (!_context_printed && !context_anno.equals("nocontext", 9)) { + String astr = combine_anno(combine_anno(_context, _context_landmark), + str.substring(str.begin(), str_endanno)); + if (astr && astr.back() != '\n') + astr += '\n'; + _context_printed = true; + return ErrorVeneer::decorate(astr + istr); + } else + return ErrorVeneer::decorate(istr); +} + + +// +// PREFIX ERROR HANDLER +// + +PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh, + const String &prefix) + : ErrorVeneer(errh), _prefix(prefix) +{ +} + +String +PrefixErrorHandler::decorate(const String &str) +{ + return ErrorVeneer::decorate(combine_anno(str, _prefix)); +} + + +// +// LANDMARK ERROR HANDLER +// + +LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark) + : ErrorVeneer(errh), _landmark(make_landmark_anno(landmark)) +{ +} + +String +LandmarkErrorHandler::decorate(const String &str) +{ + return ErrorVeneer::decorate(combine_anno(str, _landmark)); +} + + +// +// BAIL ERROR HANDLER +// + +#ifndef __KERNEL__ + +BailErrorHandler::BailErrorHandler(ErrorHandler *errh, int l) + : ErrorVeneer(errh), _level(l) +{ +} + +void +BailErrorHandler::account(int level) +{ + ErrorVeneer::account(level); + if (level <= _level) + exit(1); +} + +#endif diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/filename.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/filename.cc new file mode 100644 index 00000000000..396e81cd3c5 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/filename.cc @@ -0,0 +1,130 @@ +// -*- related-file-name: "../include/lcdf/filename.hh" -*- + +/* filename.{cc,hh} -- filenames + * + * Copyright (c) 1999-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/filename.hh> +#include <lcdf/landmark.hh> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifndef PATHNAME_SEPARATOR +# define PATHNAME_SEPARATOR '/' +#endif +#ifndef CURRENT_DIRECTORY +# define CURRENT_DIRECTORY "./" +#endif + + +Filename::Filename(const String &fn) + : _path(fn), _actual(0) +{ + if (!fn) + return; + + int last_slash = fn.find_right(PATHNAME_SEPARATOR); + if (last_slash >= 0) { + _dir = _path.substring(0, last_slash + 1); + _name = _path.substring(last_slash + 1); + } else { + _dir = CURRENT_DIRECTORY; + _name = fn; + } + + assert(_dir.back() == PATHNAME_SEPARATOR); +} + +Filename::Filename(const String &dir, const String &name) + : _name(name), _actual(0) +{ + if (!name) + return; + + if (_name[0] == PATHNAME_SEPARATOR) + _dir = ""; + else if (dir) { + _dir = dir; + if (dir.back() != PATHNAME_SEPARATOR) + _dir += PATHNAME_SEPARATOR; + } else + _dir = CURRENT_DIRECTORY; + + int slash = name.find_right(PATHNAME_SEPARATOR); + if (slash >= 0) { + _dir += name.substring(0, slash + 1); + _name = name.substring(slash + 1); + } + + _path = _dir + _name; +} + +Filename::Filename(FILE *actual, const String &name) + : _name(name), _path(name), _actual(actual) +{ +} + + +String +Filename::extension() const +{ + int dot = _name.find_right('.'); + while (dot > 0 && _name[dot - 1] == '.') + dot--; + if (dot > 0) + return _name.substring(dot + 1); + else + return String(); +} + +String +Filename::base() const +{ + if (String ex = extension()) + return _name.substring(0, _name.length() - ex.length() - 1); + else + return _name; +} + + +FILE * +Filename::open_read(bool binary) const +{ + if (_actual || !_path) + return _actual; + else + return fopen(_path.c_str(), binary ? "rb" : "r"); +} + +bool +Filename::readable() const +{ + struct stat s; + if (!_path) + return false; + return _actual || (_path && (stat(_path.c_str(), &s) >= 0)); +} + + +FILE * +Filename::open_write(bool binary) const +{ + if (_actual || !_path) + return _actual; + else + return fopen(_path.c_str(), "wb"); +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/fixlibc.c b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/fixlibc.c new file mode 100644 index 00000000000..d41238daf85 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/fixlibc.c @@ -0,0 +1,73 @@ +/* Provide definitions for missing or incorrect libc functions. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#ifdef __cplusplus +extern "C" { +#endif + +#if !HAVE_STRDUP +char * +strdup(const char *s) +{ + char *t; + int l; + if (!s) + return 0; + l = strlen(s) + 1; + t = (char *)malloc(l); + if (!t) + return 0; + memcpy(t, s, l); + return t; +} +#endif + +#if !HAVE_STRERROR +/* David Mazieres <dm@lcs.mit.edu> assures me that this definition works. */ +char * +strerror(int errno) +{ + extern int sys_nerr; + extern char *sys_errlist[]; + if (errno < 0 || errno >= sys_nerr) + return (char *)"bad error number"; + else + return sys_errlist[errno]; +} +#endif + +#if HAVE_BROKEN_STRTOD +/* On NeXTSTEP, Melissa O'Neill <oneill@cs.sfu.ca> reports that strtod + consumes whitespace after its argument, which makes mminstance (among other + programs) not work. This wrapper gets rid of that whitespace again. + (Originally, we suspected strtol too, but it seems to work, at least in + NeXTSTEP 3.3 patch 2.) */ + +double +good_strtod(const char *nptr, char **endptr) +{ + double d = strtod(nptr, endptr); + if (endptr) + while (*endptr > nptr && isspace((unsigned char) (*endptr)[-1])) + (*endptr)--; + return d; +} +#endif + +#if !HAVE_STRNLEN || HAVE_BROKEN_STRNLEN +size_t +strnlen(const char *s, size_t maxlen) +{ + const char *p = (const char *) memchr(s, 0, maxlen); + return p ? p - s : maxlen; +} +#endif + +#ifdef __cplusplus +} +#endif diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/globmatch.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/globmatch.cc new file mode 100644 index 00000000000..dcd7afc135c --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/globmatch.cc @@ -0,0 +1,116 @@ +// -*- related-file-name: "../include/lcdf/globmatch.hh" -*- + +/* globmatch.{cc,hh} -- glob_match() function for shell globbing + * + * Copyright (c) 2000-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/globmatch.hh> +#include <lcdf/string.hh> +#include <lcdf/vector.hh> + +bool +glob_match(const String& str, const String& pattern) +{ + const char* sdata = str.data(); + const char* pdata = pattern.data(); + int slen = str.length(); + int plen = pattern.length(); + int spos = 0, ppos = 0; + Vector<int> glob_ppos, glob_spos1, glob_spos2; + + while (1) { + while (ppos < plen) + switch (pdata[ppos]) { + + case '?': + if (spos >= slen) + goto done; + spos++; + ppos++; + break; + + case '*': + glob_ppos.push_back(ppos + 1); + glob_spos1.push_back(spos); + glob_spos2.push_back(slen); + spos = slen; + ppos++; + break; + + case '[': { + if (spos >= slen) + goto done; + + // find end of character class + int p = ppos + 1; + bool negated = false; + if (p < plen && pdata[p] == '^') { + negated = true; + p++; + } + int first = p; + if (p < plen && pdata[p] == ']') + p++; + while (p < plen && pdata[p] != ']') + p++; + if (p >= plen) // not a character class at all + goto ordinary; + + // parse character class + bool in = false; + for (int i = first; i < p && !in; i++) { + int c1 = pdata[i]; + int c2 = c1; + if (i < p - 2 && pdata[i+1] == '-') { + c2 = pdata[i+2]; + i += 2; + } + if (sdata[spos] >= c1 && sdata[spos] <= c2) + in = true; + } + + if ((negated && in) || (!negated && !in)) + goto done; + ppos = p + 1; + spos++; + break; + } + + default: + ordinary: + if (spos >= slen || sdata[spos] != pdata[ppos]) + goto done; + spos++; + ppos++; + break; + + } + + done: + if (spos == slen && ppos == plen) + return true; + while (glob_ppos.size() && glob_spos1.back() == glob_spos2.back()) { + glob_ppos.pop_back(); + glob_spos1.pop_back(); + glob_spos2.pop_back(); + } + if (glob_ppos.size()) { + glob_spos2.back()--; + spos = glob_spos2.back(); + ppos = glob_ppos.back(); + } else + return false; + } +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/landmark.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/landmark.cc new file mode 100644 index 00000000000..68511055ddc --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/landmark.cc @@ -0,0 +1,36 @@ +// -*- related-file-name: "../include/lcdf/landmark.hh" -*- + +/* landmark.{cc,hh} -- FILE:LINE type landmarks + * + * Copyright (c) 1998-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/landmark.hh> + +Landmark +operator+(const Landmark &landmark, int offset) +{ + if (landmark.has_line()) + return Landmark(landmark.file(), landmark.line() + offset); + else + return landmark; +} + +Landmark::operator String() const +{ + if (_file && has_line()) + return _file + ":" + String(_line); + else + return _file; +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/md5.c b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/md5.c new file mode 100644 index 00000000000..557a39bef95 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/md5.c @@ -0,0 +1,357 @@ +/* -*- mode: c; c-basic-offset: 8; related-file-name: "../include/lcdf/md5.h" -*- */ +/* md5.c - MD5 Message-Digest Algorithm + * Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc. + * + * according to the definition of MD5 in RFC 1321 from April 1992. + * NOTE: This is *not* the same file as the one from glibc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ +/* heavily modified for GnuPG by <werner.koch@guug.de> */ +/* modified again for Sylpheed by <wk@gnupg.org> 2001-02-11 */ +/* modified again for LCDF by Eddie Kohler <kohler@icir.org> */ + + +/* Test values: + * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E + * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61 + * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72 + * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0 + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <lcdf/inttypes.h> +#include <lcdf/md5.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/**************** + * Rotate a 32 bit integer by n bits + */ +#if defined(__GNUC__) && defined(__i386__) +static inline uint32_t +rol( uint32_t x, int n) +{ + __asm__("roll %%cl,%0" + :"=r" (x) + :"0" (x),"c" (n)); + return x; +} +#else +#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#endif + + +void +md5_init(MD5_CONTEXT *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->nblocks = 0; + ctx->count = 0; + ctx->finalized = 0; +} + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + + +/**************** + * transform n*64 bytes + */ +static void +transform(MD5_CONTEXT *ctx, const unsigned char *data) +{ + uint32_t correct_words[16]; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + uint32_t *cwp = correct_words; + +#if WORDS_BIGENDIAN + { + int i; + unsigned char *p2, *p1; + + for (i = 0, p1 = data, p2 = (unsigned char*)correct_words; + i < 16; i++, p2 += 4) { + p2[3] = *p1++; + p2[2] = *p1++; + p2[1] = *p1++; + p2[0] = *p1++; + } + } +#elif WORDS_LITTLEENDIAN + memcpy(correct_words, data, 64); +#else +# error "Neither WORDS_BIGENDIAN nor WORDS_LITTLEENDIAN is defined!" +#endif + + +#define OP(a, b, c, d, s, T) \ + do { \ + a += FF (b, c, d) + (*cwp++) + T; \ + a = rol(a, s); \ + a += b; \ + } while (0) + + /* Before we start, one word about the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do { \ + a += f (b, c, d) + correct_words[k] + T; \ + a = rol(a, s); \ + a += b; \ + } while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Put checksum in context given as argument. */ + ctx->A += A; + ctx->B += B; + ctx->C += C; + ctx->D += D; +} + + + +/* The routine updates the message-digest context to + * account for the presence of each of the characters inBuf[0..inLen-1] + * in the message whose digest is being computed. + */ +void +md5_update(MD5_CONTEXT *hd, const unsigned char *inbuf, size_t inlen) +{ + if (hd->count == 64) { /* flush the buffer */ + transform( hd, hd->buf ); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + if (hd->count) { + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; + md5_update(hd, NULL, 0); + if (!inlen) + return; + } + + while (inlen >= 64) { + transform(hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + + + +/* The routine final terminates the message-digest computation and + * ends with the desired message digest in mdContext->digest[0...15]. + * The handle is prepared for a new MD5 cycle. + * Returns 16 bytes representing the digest. + */ + +static void +do_final(MD5_CONTEXT *hd) +{ + uint32_t t, msb, lsb; + unsigned char *p; + + md5_update(hd, NULL, 0); /* flush */ + + msb = 0; + t = hd->nblocks; + if ((lsb = t << 6) < t) /* multiply by 64 to make a byte count */ + msb++; + msb += t >> 26; + t = lsb; + if ((lsb = t + hd->count) < t) /* add the count */ + msb++; + t = lsb; + if ((lsb = t << 3) < t) /* multiply by 8 to make a bit count */ + msb++; + msb += t >> 29; + + if (hd->count < 56) { /* enough room */ + hd->buf[hd->count++] = 0x80; /* pad */ + while(hd->count < 56) + hd->buf[hd->count++] = 0; /* pad */ + } else { /* need one extra block */ + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < 64) + hd->buf[hd->count++] = 0; + md5_update(hd, NULL, 0); /* flush */ + memset(hd->buf, 0, 56); /* fill next block with zeroes */ + } + + /* append the 64 bit count */ + hd->buf[56] = lsb ; + hd->buf[57] = lsb >> 8; + hd->buf[58] = lsb >> 16; + hd->buf[59] = lsb >> 24; + hd->buf[60] = msb ; + hd->buf[61] = msb >> 8; + hd->buf[62] = msb >> 16; + hd->buf[63] = msb >> 24; + transform(hd, hd->buf); + + p = hd->buf; +#if WORDS_BIGENDIAN +#define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ + *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) +#elif WORDS_LITTLEENDIAN + /*#define X(a) do { *(uint32_t*)p = hd->##a ; p += 4; } while(0)*/ + /* Unixware's cpp doesn't like the above construct so we do it his way: + * (reported by Allan Clark) */ +#define X(a) do { *(uint32_t*)p = (*hd).a ; p += 4; } while(0) +#else +# error "Neither WORDS_BIGENDIAN nor WORDS_LITTLEENDIAN is defined!" +#endif + X(A); + X(B); + X(C); + X(D); +#undef X + hd->finalized = 1; +} + +void +md5_final(unsigned char *digest, MD5_CONTEXT *ctx) +{ + if (!ctx->finalized) + do_final(ctx); + memcpy(digest, ctx->buf, 16); +} + +void +md5_final_text(char *buf, MD5_CONTEXT *ctx) +{ + static const char *chars = "abcdefghijklmnopqrstuvwxyz234567"; + int bit; + if (!ctx->finalized) + do_final(ctx); + for (bit = 0; bit < 16*8; bit += 5) { + int first_char = bit / 8; + int val = ctx->buf[first_char] >> (bit % 8); + if (bit + 8 > (first_char + 1) * 8 && first_char < 15) + val += ctx->buf[first_char + 1] << (8 - (bit % 8)); + *buf++ = chars[val & 0x1F]; + } + *buf++ = 0; +} + + +#ifdef __cplusplus +} +#endif diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/permstr.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/permstr.cc new file mode 100644 index 00000000000..c6aebab31e7 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/permstr.cc @@ -0,0 +1,319 @@ +// -*- related-file-name: "../include/lcdf/permstr.hh" -*- + +/* permstr.{cc,hh} -- permanent strings + * + * Copyright (c) 1998-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/permstr.hh> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +static PermString::Initializer initializer; + +PermString::Doodad PermString::zero_char_doodad = { + 0, 0, { 0, 0 } +}; +PermString::Doodad PermString::one_char_doodad[256]; +PermString::Doodad* PermString::buckets[NHASH]; + +PermString::Initializer::Initializer() +{ + static int initialized = 0; + if (!initialized) { + PermString::static_initialize(); + initialized = 1; + } +} + +void +PermString::static_initialize() +{ + for (int i = 0; i < 256; i++) { + one_char_doodad[i].next = 0; + one_char_doodad[i].length = 1; + one_char_doodad[i].data[0] = i; + one_char_doodad[i].data[1] = 0; + } +} + + +// This scatter array, and the ideas behind it, are stolen from lcc. +static int scatter[] = { /* map characters to random values */ + 2078917053, 143302914, 1027100827, 1953210302, 755253631, + 2002600785, 1405390230, 45248011, 1099951567, 433832350, + 2018585307, 438263339, 813528929, 1703199216, 618906479, + 573714703, 766270699, 275680090, 1510320440, 1583583926, + 1723401032, 1965443329, 1098183682, 1636505764, 980071615, + 1011597961, 643279273, 1315461275, 157584038, 1069844923, + 471560540, 89017443, 1213147837, 1498661368, 2042227746, + 1968401469, 1353778505, 1300134328, 2013649480, 306246424, + 1733966678, 1884751139, 744509763, 400011959, 1440466707, + 1363416242, 973726663, 59253759, 1639096332, 336563455, + 1642837685, 1215013716, 154523136, 593537720, 704035832, + 1134594751, 1605135681, 1347315106, 302572379, 1762719719, + 269676381, 774132919, 1851737163, 1482824219, 125310639, + 1746481261, 1303742040, 1479089144, 899131941, 1169907872, + 1785335569, 485614972, 907175364, 382361684, 885626931, + 200158423, 1745777927, 1859353594, 259412182, 1237390611, + 48433401, 1902249868, 304920680, 202956538, 348303940, + 1008956512, 1337551289, 1953439621, 208787970, 1640123668, + 1568675693, 478464352, 266772940, 1272929208, 1961288571, + 392083579, 871926821, 1117546963, 1871172724, 1771058762, + 139971187, 1509024645, 109190086, 1047146551, 1891386329, + 994817018, 1247304975, 1489680608, 706686964, 1506717157, + 579587572, 755120366, 1261483377, 884508252, 958076904, + 1609787317, 1893464764, 148144545, 1415743291, 2102252735, + 1788268214, 836935336, 433233439, 2055041154, 2109864544, + 247038362, 299641085, 834307717, 1364585325, 23330161, + 457882831, 1504556512, 1532354806, 567072918, 404219416, + 1276257488, 1561889936, 1651524391, 618454448, 121093252, + 1010757900, 1198042020, 876213618, 124757630, 2082550272, + 1834290522, 1734544947, 1828531389, 1982435068, 1002804590, + 1783300476, 1623219634, 1839739926, 69050267, 1530777140, + 1802120822, 316088629, 1830418225, 488944891, 1680673954, + 1853748387, 946827723, 1037746818, 1238619545, 1513900641, + 1441966234, 367393385, 928306929, 946006977, 985847834, + 1049400181, 1956764878, 36406206, 1925613800, 2081522508, + 2118956479, 1612420674, 1668583807, 1800004220, 1447372094, + 523904750, 1435821048, 923108080, 216161028, 1504871315, + 306401572, 2018281851, 1820959944, 2136819798, 359743094, + 1354150250, 1843084537, 1306570817, 244413420, 934220434, + 672987810, 1686379655, 1301613820, 1601294739, 484902984, + 139978006, 503211273, 294184214, 176384212, 281341425, + 228223074, 147857043, 1893762099, 1896806882, 1947861263, + 1193650546, 273227984, 1236198663, 2116758626, 489389012, + 593586330, 275676551, 360187215, 267062626, 265012701, + 719930310, 1621212876, 2108097238, 2026501127, 1865626297, + 894834024, 552005290, 1404522304, 48964196, 5816381, + 1889425288, 188942202, 509027654, 36125855, 365326415, + 790369079, 264348929, 513183458, 536647531, 13672163, + 313561074, 1730298077, 286900147, 1549759737, 1699573055, + 776289160, 2143346068, 1975249606, 1136476375, 262925046, + 92778659, 1856406685, 1884137923, 53392249, 1735424165, + 1602280572 +}; + + +void +PermString::initialize(const char* s, int length) +{ + const unsigned char* m = reinterpret_cast<const unsigned char*>(s); + const unsigned char* mm; + + if (length < 0) + length = (s ? strlen(s) : 0); + + if (length == 0) { + _rep = zero_char_doodad.data; + return; + } else if (length == 1) { + _rep = one_char_doodad[m[0]].data; + return; + } + + unsigned hash; + int l; + for (hash = 0, l = length, mm = m; l; mm++, l--) + hash = (hash << 1) + scatter[*mm]; + hash &= (NHASH - 1); + + Doodad *buck; + for (buck = buckets[hash]; buck; buck = buck->next) + if (length == buck->length && memcmp(s, buck->data, length) == 0) { + _rep = buck->data; + return; + } + + // CANNOT USE new because the structure has variable size. + buck = (Doodad *)malloc(sizeof(Doodad) + length - 1); + buck->next = buckets[hash]; + buckets[hash] = buck; + buck->length = length; + memcpy(buck->data, s, length); + buck->data[length] = 0; + + _rep = buck->data; +} + +static int pspos; +static int pscap = 64; +static char *psc = (char *)malloc(pscap); + +static void +append(const char *s, int len) +{ + if (pspos + len >= pscap) { + pscap *= 2; + psc = (char *)realloc(psc, pscap); + } + memcpy(psc + pspos, s, len); + pspos += len; +} + +inline static void +extend(int len) +{ + while (pspos + len >= pscap) { + pscap *= 2; + psc = (char *)realloc(psc, pscap); + } +} + +PermString +vpermprintf(const char *s, va_list val) +{ + pspos = 0; + while (1) { + + const char *pct = strchr(s, '%'); + if (!pct) { + if (*s) + append(s, strlen(s)); + break; + } + if (pct != s) { + append(s, pct - s); + s = pct; + } + + int iflag = -1; + while (1) + switch (*++s) { + + case '0': + /* zeroflag = 1; */ + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + assert(iflag == -1 /* Too many decimal flags in permprintf */); + iflag = 0; + while (*s >= '0' && *s <= '9') { + iflag = iflag * 10 + *s - '0'; + s++; + } + break; + + case '*': + assert(iflag == -1 /* iflag given */); + iflag = va_arg(val, int); + break; + + case 's': { + const char *x = va_arg(val, const char *); + if (x) { + if (iflag < 0) + append(x, strlen(x)); + else + append(x, iflag); + } + goto pctdone; + } + + case 'c': { + char c = (char)(va_arg(val, int) & 0xFF); + append(&c, 1); + goto pctdone; + } + + case 'p': { + PermString::Capsule x = va_arg(val, PermString::Capsule); + PermString px; + if (x) + px = PermString::decapsule(x); + if (iflag < 0 || iflag > px.length()) + append(px.c_str(), px.length()); + else + append(px.c_str(), iflag); + goto pctdone; + } + + case 'd': { + // FIXME FIXME rewrite for sense + int x = va_arg(val, int); + if (pspos == pscap) + extend(1); + + // FIXME -2^31 + unsigned int ux = x; + if (x < 0) { + psc[pspos++] = '-'; + ux = -x; + } + + int numdigits = 0; + for (unsigned digcountx = ux; digcountx > 9; digcountx /= 10) + numdigits++; + + extend(numdigits + 1); + int digit = numdigits; + do { + psc[pspos + digit] = (ux % 10) + '0'; + ux /= 10; + digit--; + } while (ux); + pspos += numdigits + 1; + + goto pctdone; + } + + case 'g': { + // FIXME FIXME rewrite for sense + double x = va_arg(val, double); + char buffer[1000]; + int len; + sprintf(buffer, "%.10g%n", x, &len); + extend(len); + strcpy(psc + pspos, buffer); + pspos += len; + goto pctdone; + } + + default: + assert(0 /* Bad % in permprintf */); + goto pctdone; + + } + + pctdone: + s++; + } + + return PermString(psc, pspos); +} + +PermString permprintf(const char *s, ...) +{ + va_list val; + va_start(val, s); + PermString p = vpermprintf(s, val); + va_end(val); + return p; +} + +PermString permcat(PermString a, PermString b) +{ + if (!a || !b) + return a ? a : b; + unsigned al = a.length(); + unsigned bl = b.length(); + char *s = new char[al + bl]; + memcpy(s, a.c_str(), al); + memcpy(s + al, b.c_str(), bl); + PermString p(s, al + bl); + delete[] s; + return p; +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/point.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/point.cc new file mode 100644 index 00000000000..8b23fdcb571 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/point.cc @@ -0,0 +1,57 @@ +// -*- related-file-name: "../include/lcdf/point.hh" -*- + +/* point.{cc,hh} -- 2D points + * + * Copyright (c) 1998-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/point.hh> + +Point +Point::rotated(double rotation) const throw () +{ + double r = length(); + double theta = angle() + rotation; + return Point(r * cos(theta), r * sin(theta)); +} + +Point +Point::midpoint(const Point &a, const Point &b) throw () +{ + return Point((a.x + b.x)/2, (a.y + b.y)/2); +} + +bool +Point::on_line(const Point &a, const Point &b, double tolerance) const throw () +{ + Point c = b - a; + double d = c.x * (y - a.y) - c.y * (x - a.x); + return (d * d <= tolerance * tolerance * c.squared_length()); +} + +bool +Point::on_segment(const Point &a, const Point &b, double t) const throw () +{ + double tt; + Point c = b - a; + if (fabs(c.x) > fabs(c.y)) + tt = (x - a.x) / c.x; + else if (c.y) + tt = (y - a.y) / c.y; + else + tt = 0; + if (tt < 0 || tt > 1) + return 0; + return on_line(a, b, t); +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/slurper.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/slurper.cc new file mode 100644 index 00000000000..e089617705d --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/slurper.cc @@ -0,0 +1,187 @@ +// -*- related-file-name: "../include/lcdf/slurper.hh" -*- + +/* slurper.{cc,hh} -- reading from files a line at a time + * + * Copyright (c) 1998-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/slurper.hh> +#include <string.h> + +static const int DefChunkCap = 2048; +static const int WorthMoving = 256; + + +Slurper::Slurper(const Filename &filename, FILE *f) + : _filename(filename), _lineno(0), + _data(new unsigned char[DefChunkCap]), _cap(DefChunkCap), + _pos(0), _len(0), _line(0), _line_len(0), + _saved_line(false), _at_eof(false) +{ + if (f) { + _f = f; + _own_f = false; + } else { + _f = _filename.open_read(); + _own_f = true; + } +} + +Slurper::~Slurper() +{ + delete[] _data; + if (_f && _own_f) fclose(_f); +} + + +void +Slurper::grow_buffer() +{ + // If we need to keep the upper part of the buffer, shift it down (moving + // any data we care about). + if (_pos >= _cap - WorthMoving) { + // I used to move it myself, with a comment that SunOS didn't have a + // correct implementation of memmove. This should be detected by + // configure, if it's really a problem. + memmove(_data, _data + _pos, _len - _pos); + _len -= _pos; + _pos = 0; + } + + // Grow the buffer if necessary. + if (_len >= _cap) { + unsigned char *new_data = new unsigned char[ 2 * _cap ]; + // I can't believe I didn't have the line below!! + memcpy(new_data, _data, _len); + delete[] _data; + _data = new_data; + _cap = 2 * _cap; + } +} + + +inline int +Slurper::more_data() +{ + grow_buffer(); + + // Read new data into the buffer. + int amount = fread(_data + _len, 1, _cap - _len, _f); + _len += amount; + return amount; +} + +char * +Slurper::get_line_at(unsigned pos) +{ + while (1) { + for (; pos < _len; pos++) + if (_data[pos] == '\n' || _data[pos] == '\r') + goto line_ends_at_pos; + + // no line end? look for more data. save and reset `pos', since _pos + // may change. + int offset = pos - _pos; + bool got_more_data = more_data() != 0; + pos = _pos + offset; + if (!got_more_data) { + _at_eof = true; + goto line_ends_at_pos; + } + } + + line_ends_at_pos: + + // PRECONDITION: the line starts at _pos and ends at pos. + unsigned next_pos; + + // Find beginning of next line. 3 cases: + // 1. line ends in \r\n -> _pos = pos + 2; + // 2. line ends in \r OR \n -> _pos = pos + 1; + // 3. neither -> must be last line in file; _pos = pos, + // since pos == _len + if (pos == _len) { + // last line in file didn't end in `\n': must have no data left + // ensure we have enough space for terminating nul + if (pos == _cap) grow_buffer(); + next_pos = pos; + // if already at EOF, don't increment the line number + if (pos == _pos) _lineno--; + + } else if (_data[pos] == '\n') + next_pos = pos + 1; + + else { + assert(_data[pos] == '\r'); + // If `\r' is last char in buffer, `\n' might be next char. Must read more + // data to check for it, or we'd report an empty line that didn't really + // exist. + if (pos == _len - 1) { + // be careful about the possible shift of _pos and _len! + int offset = pos - _pos; + more_data(); + pos = _pos + offset; + } + if (pos < _len - 1 && _data[pos + 1] == '\n') + next_pos = pos + 2; + else + next_pos = pos + 1; + } + + _line = _data + _pos; + _line_len = pos - _pos; + _data[pos] = 0; + _pos = next_pos; + _lineno++; + return (char *)_line; +} + +char * +Slurper::next_line() +{ + if (_saved_line) { + _saved_line = false; + return (char *)_line; + } + get_line_at(_pos); + if (_line_len == 0 && _at_eof) + _line = 0; + return (char *)_line; +} + +char * +Slurper::peek_line() +{ + next_line(); + _saved_line = true; + return (char *)_line; +} + +char * +Slurper::append_next_line() +{ + unsigned delta = (_data + _pos) - (_line + _line_len); + if (_len - _pos > _line_len) { + memmove(_line + delta, _line, _line_len); + _line += delta; + } else { + memmove(_data + _pos - delta, _data + _pos, _len - _pos); + _pos -= delta; + _len -= delta; + } + + unsigned append_at = _pos; + _pos = _line - _data; + return get_line_at(append_at); +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/straccum.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/straccum.cc new file mode 100644 index 00000000000..f31b9e216fc --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/straccum.cc @@ -0,0 +1,304 @@ +// -*- related-file-name: "../include/lcdf/straccum.hh" -*- +/* + * straccum.{cc,hh} -- build up strings with operator<< + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * Copyright (c) 2001-2012 Eddie Kohler + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/straccum.hh> +#include <lcdf/vector.hh> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> + +/** @class StringAccum + * @brief Efficiently build up Strings from pieces. + * + * Like the String class, StringAccum represents a string of characters. + * However, unlike a String, a StringAccum is inherently mutable, and + * efficiently supports building up a large string from many smaller pieces. + * + * StringAccum objects support operator<<() operations for most fundamental + * data types. A StringAccum is generally built up by operator<<(), and then + * turned into a String by the take_string() method. Extracting the String + * from a StringAccum does no memory allocation or copying; the StringAccum's + * memory is donated to the String. + * + * <h3>Out-of-memory StringAccums</h3> + * + * When there is not enough memory to add requested characters to a + * StringAccum object, the object becomes a special "out-of-memory" + * StringAccum. Out-of-memory objects are contagious: the result of any + * concatenation operation involving an out-of-memory StringAccum is another + * out-of-memory StringAccum. Appending an out-of-memory String with "sa << + * s" makes "sa" out-of-memory. (However, other usually-equivalent calls, + * such as "sa.append(s.begin(), s.end())", <em>do not</em> make "sa" + * out-of-memory.) Calling take_string() on an out-of-memory StringAccum + * returns an out-of-memory String. + * + * Out-of-memory StringAccum objects have length zero. + */ + + +void +StringAccum::assign_out_of_memory() +{ + assert(_cap >= 0); + if (_cap > 0) + delete[] (_s - MEMO_SPACE); + _s = reinterpret_cast<unsigned char *>(const_cast<char *>(String::out_of_memory_data())); + _cap = -1; + _len = 0; +} + +char * +StringAccum::grow(int want) +{ + // can't append to out-of-memory strings + if (_cap < 0) { + errno = ENOMEM; + return 0; + } + + int ncap = (_cap ? (_cap + MEMO_SPACE) * 2 : 128) - MEMO_SPACE; + while (ncap <= want) + ncap = (ncap + MEMO_SPACE) * 2 - MEMO_SPACE; + + unsigned char *n = new unsigned char[ncap + MEMO_SPACE]; + if (!n) { + assign_out_of_memory(); + errno = ENOMEM; + return 0; + } + n += MEMO_SPACE; + + if (_s) { + memcpy(n, _s, _len); + delete[] (_s - MEMO_SPACE); + } + _s = n; + _cap = ncap; + return reinterpret_cast<char *>(_s + _len); +} + +int +StringAccum::resize(int len) +{ + assert(len >= 0); + if (len > _cap && !grow(len)) + return -ENOMEM; + else { + _len = len; + return 0; + } +} + +char * +StringAccum::hard_extend(int nadjust, int nreserve) +{ + char *x = grow(_len + nadjust + nreserve); + if (x) + _len += nadjust; + return x; +} + +const char * +StringAccum::c_str() +{ + if (_len < _cap || grow(_len)) + _s[_len] = '\0'; + return reinterpret_cast<char *>(_s); +} + +void +StringAccum::append_fill(int c, int len) +{ + if (char *s = extend(len)) + memset(s, c, len); +} + +void +StringAccum::append_utf8_hard(unsigned ch) +{ + if (ch < 0x80) + append((unsigned char) ch); + else if (ch < 0x800) { + append((unsigned char) (0xC0 + ((ch >> 6) & 0x1F))); + append((unsigned char) (0x80 + (ch & 0x3F))); + } else if (ch < 0x10000) { + append((unsigned char) (0xE0 + ((ch >> 12) & 0x0F))); + append((unsigned char) (0x80 + ((ch >> 6) & 0x3F))); + append((unsigned char) (0x80 + (ch & 0x3F))); + } else if (ch < 0x110000) { + append((unsigned char) (0xF0 + ((ch >> 18) & 0x07))); + append((unsigned char) (0x80 + ((ch >> 12) & 0x3F))); + append((unsigned char) (0x80 + ((ch >> 6) & 0x3F))); + append((unsigned char) (0x80 + (ch & 0x3F))); + } else + append((unsigned char) '?'); +} + +void +StringAccum::hard_append(const char *s, int len) +{ + // We must be careful about calls like "sa.append(sa.begin(), sa.end())"; + // a naive implementation might use sa's data after freeing it. + const char *my_s = reinterpret_cast<char *>(_s); + + if (_len + len <= _cap) { + success: + memcpy(_s + _len, s, len); + _len += len; + } else if (s < my_s || s >= my_s + _cap) { + if (grow(_len + len)) + goto success; + } else { + unsigned char *old_s = _s; + int old_len = _len; + + _s = 0; + _len = 0; + _cap = 0; + + if (char *new_s = extend(old_len + len)) { + memcpy(new_s, old_s, old_len); + memcpy(new_s + old_len, s, len); + } + + delete[] (old_s - MEMO_SPACE); + } +} + +void +StringAccum::append(const char *s) +{ + hard_append(s, strlen(s)); +} + +String +StringAccum::take_string() +{ + int len = length(); + int cap = _cap; + char *str = reinterpret_cast<char *>(_s); + if (len > 0) { + _s = 0; + _len = _cap = 0; + return String::make_claim(str, len, cap); + } else if (!out_of_memory()) + return String(); + else { + clear(); + return String::make_out_of_memory(); + } +} + +void +StringAccum::swap(StringAccum &o) +{ + unsigned char *os = o._s; + int olen = o._len, ocap = o._cap; + o._s = _s; + o._len = _len, o._cap = _cap; + _s = os; + _len = olen, _cap = ocap; +} + +/** @relates StringAccum + @brief Append decimal representation of @a i to @a sa. + @return @a sa */ +StringAccum & +operator<<(StringAccum &sa, long i) +{ + if (char *x = sa.reserve(24)) { + int len = sprintf(x, "%ld", i); + sa.adjust_length(len); + } + return sa; +} + +/** @relates StringAccum + @brief Append decimal representation of @a u to @a sa. + @return @a sa */ +StringAccum & +operator<<(StringAccum &sa, unsigned long u) +{ + if (char *x = sa.reserve(24)) { + int len = sprintf(x, "%lu", u); + sa.adjust_length(len); + } + return sa; +} + +StringAccum & +operator<<(StringAccum &sa, double d) +{ + if (char *x = sa.reserve(256)) { + int len = sprintf(x, "%.12g", d); + sa.adjust_length(len); + } + return sa; +} + +StringAccum & +StringAccum::snprintf(int n, const char *format, ...) +{ + va_list val; + va_start(val, format); + if (char *x = reserve(n + 1)) { +#if HAVE_VSNPRINTF + int len = vsnprintf(x, n + 1, format, val); +#else + int len = vsprintf(x, format, val); + assert(len <= n); +#endif + adjust_length(len); + } + va_end(val); + return *this; +} + +void +StringAccum::append_break_lines(const String& text, int linelen, const String &leftmargin) +{ + if (text.length() == 0) + return; + const char* line = text.begin(); + const char* ends = text.end(); + linelen -= leftmargin.length(); + for (const char* s = line; s < ends; s++) { + const char* start = s; + while (s < ends && isspace((unsigned char) *s)) + s++; + const char* word = s; + while (s < ends && !isspace((unsigned char) *s)) + s++; + if (s - line > linelen && start > line) { + *this << leftmargin; + append(line, start - line); + *this << '\n'; + line = word; + } + } + if (line < text.end()) { + *this << leftmargin; + append(line, text.end() - line); + *this << '\n'; + } +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/string.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/string.cc new file mode 100644 index 00000000000..ec14c378f20 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/string.cc @@ -0,0 +1,786 @@ +// -*- related-file-name: "../include/lcdf/string.hh" -*- +/* + * string.{cc,hh} -- a String class with shared substrings + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * Copyright (c) 2001-2012 Eddie Kohler + * Copyright (c) 2008-2009 Meraki, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/string.hh> +#include <lcdf/straccum.hh> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <lcdf/inttypes.h> + +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif + +/** @file string.hh + * @brief The LCDF String class. + */ + +/** @class String + * @brief A string of characters. + * + * The String class represents a string of characters. Strings may be + * constructed from C strings, characters, numbers, and so forth. They may + * also be added together. The underlying character arrays are dynamically + * allocated; String operations allocate and free memory as needed. A String + * and its substrings generally share memory. Accessing a character by index + * takes O(1) time; so does creating a substring. + * + * <h3>Out-of-memory strings</h3> + * + * When there is not enough memory to create a particular string, a special + * "out-of-memory" string is returned instead. Out-of-memory strings are + * contagious: the result of any concatenation operation involving an + * out-of-memory string is another out-of-memory string. Thus, the final + * result of a series of String operations will be an out-of-memory string, + * even if the out-of-memory condition occurs in the middle. + * + * Out-of-memory strings have zero characters, but they aren't equal to other + * empty strings. If @a s is a normal String (even an empty string), and @a + * oom is an out-of-memory string, then @a s @< @a oom. + * + * All out-of-memory strings are equal and share the same data(), which is + * different from the data() of any other string. See + * String::out_of_memory_data(). The String::make_out_of_memory() function + * returns an out-of-memory string. + */ + +const char String::null_data = '\0'; +const char String::oom_data = '\0'; +const char String::bool_data[] = "true\0false"; +const char String::int_data[] = "0\0001\0002\0003\0004\0005\0006\0007\0008\0009"; + +#if HAVE_STRING_PROFILING > 1 +# define MEMO_INITIALIZER_TAIL , 0, 0 +#else +# define MEMO_INITIALIZER_TAIL +#endif + +const String::rep_t String::null_string_rep = { + &null_data, 0, 0 +}; +const String::rep_t String::oom_string_rep = { + &oom_data, 0, 0 +}; + +#if HAVE_STRING_PROFILING +uint64_t String::live_memo_count; +uint64_t String::memo_sizes[55]; +uint64_t String::live_memo_sizes[55]; +uint64_t String::live_memo_bytes[55]; +# if HAVE_STRING_PROFILING > 1 +String::memo_t *String::live_memos[55]; +# endif +#endif + +/** @cond never */ +String::memo_t * +String::create_memo(char *space, int dirty, int capacity) +{ + assert(capacity > 0 && capacity >= dirty); + memo_t *memo; + if (space) + memo = reinterpret_cast<memo_t *>(space); + else + memo = reinterpret_cast<memo_t *>(new char[MEMO_SPACE + capacity]); + if (memo) { + memo->capacity = capacity; + memo->dirty = dirty; + memo->refcount = (space ? 0 : 1); +#if HAVE_STRING_PROFILING + int bucket = profile_memo_size_bucket(dirty, capacity); + ++memo_sizes[bucket]; + ++live_memo_sizes[bucket]; + live_memo_bytes[bucket] += capacity; + ++live_memo_count; +# if HAVE_STRING_PROFILING > 1 + memo->pprev = &live_memos[bucket]; + if ((memo->next = *memo->pprev)) + memo->next->pprev = &memo->next; + *memo->pprev = memo; +# endif +#endif + } + return memo; +} + +void +String::delete_memo(memo_t *memo) +{ + assert(memo->capacity > 0); + assert(memo->capacity >= memo->dirty); +#if HAVE_STRING_PROFILING + int bucket = profile_memo_size_bucket(memo->dirty, memo->capacity); + --live_memo_sizes[bucket]; + live_memo_bytes[bucket] -= memo->capacity; + --live_memo_count; +# if HAVE_STRING_PROFILING > 1 + if ((*memo->pprev = memo->next)) + memo->next->pprev = memo->pprev; +# endif +#endif + delete[] reinterpret_cast<char *>(memo); +} + + +#if HAVE_STRING_PROFILING +void +String::one_profile_report(StringAccum &sa, int i, int examples) +{ + if (i <= 16) + sa << "memo_dirty_" << i; + else if (i < 25) { + uint32_t s = (i - 17) * 2 + 17; + sa << "memo_cap_" << s << '_' << (s + 1); + } else if (i < 29) { + uint32_t s = (i - 25) * 8 + 33; + sa << "memo_cap_" << s << '_' << (s + 7); + } else { + uint32_t s1 = (1U << (i - 23)) + 1; + uint32_t s2 = (s1 - 1) << 1; + sa << "memo_cap_" << s1 << '_' << s2; + } + sa << '\t' << live_memo_sizes[i] << '\t' << memo_sizes[i] << '\t' << live_memo_bytes[i] << '\n'; + if (examples) { +# if HAVE_STRING_PROFILING > 1 + for (memo_t *m = live_memos[i]; m; m = m->next) { + sa << " [" << m->dirty << "] "; + uint32_t dirty = m->dirty; + if (dirty > 0 && m->real_data[dirty - 1] == '\0') + --dirty; + sa.append(m->real_data, dirty > 128 ? 128 : dirty); + sa << '\n'; + } +# endif + } +} + +void +String::profile_report(StringAccum &sa, int examples) +{ + uint64_t all_live_sizes = 0, all_sizes = 0, all_live_bytes = 0; + for (int i = 0; i < 55; ++i) { + if (memo_sizes[i]) + one_profile_report(sa, i, examples); + all_live_sizes += live_memo_sizes[i]; + all_sizes += memo_sizes[i]; + all_live_bytes += live_memo_bytes[i]; + } + sa << "memo_total\t" << all_live_sizes << '\t' << all_sizes << '\t' << all_live_bytes << '\n'; +} +#endif + +/** @endcond never */ + + +/** @brief Construct a base-10 string representation of @a x. */ +String::String(int x) +{ + if (x >= 0 && x < 10) + assign_memo(int_data + 2 * x, 1, 0); + else { + char buf[128]; + sprintf(buf, "%d", x); + assign(buf, -1, false); + } +} + +/** @overload */ +String::String(unsigned x) +{ + if (x < 10) + assign_memo(int_data + 2 * x, 1, 0); + else { + char buf[128]; + sprintf(buf, "%u", x); + assign(buf, -1, false); + } +} + +/** @overload */ +String::String(long x) +{ + if (x >= 0 && x < 10) + assign_memo(int_data + 2 * x, 1, 0); + else { + char buf[128]; + sprintf(buf, "%ld", x); + assign(buf, -1, false); + } +} + +/** @overload */ +String::String(unsigned long x) +{ + if (x < 10) + assign_memo(int_data + 2 * x, 1, 0); + else { + char buf[128]; + sprintf(buf, "%lu", x); + assign(buf, -1, false); + } +} + +String::String(double x) +{ + char buf[128]; + int len = sprintf(buf, "%.12g", x); + assign(buf, len, false); +} + +String +String::make_claim(char *str, int len, int capacity) +{ + assert(str && len > 0 && capacity >= len); + memo_t *new_memo = create_memo(str - MEMO_SPACE, len, capacity); + return String(str, len, new_memo); +} + +String +String::make_stable(const char *s, int len) +{ + if (len < 0) + len = (s ? strlen(s) : 0); + return String(s, len, 0); +} + +String +String::make_fill(int c, int len) +{ + String s; + s.append_fill(c, len); + return s; +} + +void +String::assign_out_of_memory() +{ + if (_r.memo) + deref(); + _r.memo = 0; + _r.data = &oom_data; + _r.length = 0; +} + +void +String::assign(const char *s, int len, bool need_deref) +{ + if (!s) { + assert(len <= 0); + len = 0; + } else if (len < 0) + len = strlen(s); + + // need to start with dereference + if (need_deref) { + if (unlikely(_r.memo + && s >= _r.memo->real_data + && s + len <= _r.memo->real_data + _r.memo->capacity)) { + // Be careful about "String s = ...; s = s.c_str();" + _r.data = s; + _r.length = len; + return; + } else + deref(); + } + + if (len == 0) { + _r.memo = 0; + _r.data = (s == &oom_data ? s : &null_data); + + } else { + // Make the memo a multiple of 16 characters and bigger than 'len'. + int memo_capacity = (len + 15 + MEMO_SPACE) & ~15; + _r.memo = create_memo(0, len, memo_capacity - MEMO_SPACE); + if (!_r.memo) { + assign_out_of_memory(); + return; + } + memcpy(_r.memo->real_data, s, len); + _r.data = _r.memo->real_data; + } + + _r.length = len; +} + +/** @brief Append @a len unknown characters to this string. + * @return Modifiable pointer to the appended characters. + * + * The caller may safely modify the returned memory. Null is returned if + * the string becomes out-of-memory. */ +char * +String::append_uninitialized(int len) +{ + // Appending anything to "out of memory" leaves it as "out of memory" + if (unlikely(len <= 0) || out_of_memory()) + return 0; + + // If we can, append into unused space. First, we check that there's + // enough unused space for 'len' characters to fit; then, we check + // that the unused space immediately follows the data in '*this'. + uint32_t dirty; + if (_r.memo + && ((dirty = _r.memo->dirty), _r.memo->capacity > dirty + len)) { + char *real_dirty = _r.memo->real_data + dirty; + if (real_dirty == _r.data + _r.length) { + _r.memo->dirty = dirty + len; + _r.length += len; + assert(_r.memo->dirty < _r.memo->capacity); +#if HAVE_STRING_PROFILING + profile_update_memo_dirty(_r.memo, dirty, dirty + len, _r.memo->capacity); +#endif + return real_dirty; + } + } + + // Now we have to make new space. Make sure the memo is a multiple of 16 + // bytes and that it is at least 16. But for large strings, allocate a + // power of 2, since power-of-2 sizes minimize waste in frequently-used + // allocators, like Linux kmalloc. + int want_memo_len = _r.length + len + MEMO_SPACE; + int memo_capacity; + if (want_memo_len <= 1024) + memo_capacity = (want_memo_len + 15) & ~15; + else + for (memo_capacity = 2048; memo_capacity < want_memo_len; ) + memo_capacity *= 2; + + memo_t *new_memo = create_memo(0, _r.length + len, memo_capacity - MEMO_SPACE); + if (!new_memo) { + assign_out_of_memory(); + return 0; + } + + char *new_data = new_memo->real_data; + memcpy(new_data, _r.data, _r.length); + + deref(); + _r.data = new_data; + new_data += _r.length; // now new_data points to the garbage + _r.length += len; + _r.memo = new_memo; + return new_data; +} + +void +String::append(const char *s, int len, memo_t *memo) +{ + if (!s) { + assert(len <= 0); + len = 0; + } else if (len < 0) + len = strlen(s); + + if (s == &oom_data) + // Appending "out of memory" to a regular string makes it "out of + // memory" + assign_out_of_memory(); + else if (len == 0) + /* do nothing */; + else if (_r.length == 0 && memo && !out_of_memory()) { + deref(); + assign_memo(s, len, memo); + } else if (likely(!(_r.memo + && s >= _r.memo->real_data + && s + len <= _r.memo->real_data + _r.memo->capacity))) { + if (char *space = append_uninitialized(len)) + memcpy(space, s, len); + } else { + String preserve_s(*this); + if (char *space = append_uninitialized(len)) + memcpy(space, s, len); + } +} + +/** @brief Append @a len copies of character @a c to this string. */ +void +String::append_fill(int c, int len) +{ + assert(len >= 0); + if (char *space = append_uninitialized(len)) + memset(space, c, len); +} + +/** @brief Ensure the string's data is unshared and return a mutable + pointer to it. */ +char * +String::mutable_data() +{ + // If _memo has a capacity (it's not one of the special strings) and it's + // uniquely referenced, return _data right away. + if (_r.memo && _r.memo->refcount == 1) + return const_cast<char *>(_r.data); + + // Otherwise, make a copy of it. Rely on: deref() doesn't change _data or + // _length; and if _capacity == 0, then deref() doesn't free _real_data. + assert(!_r.memo || _r.memo->refcount > 1); + // But in multithreaded situations we must hold a local copy of memo! + String do_not_delete_underlying_memo(*this); + deref(); + assign(_r.data, _r.length, false); + return const_cast<char *>(_r.data); +} + +char * +String::mutable_c_str() +{ + (void) mutable_data(); + (void) c_str(); + return const_cast<char *>(_r.data); +} + +/** @brief Return a substring of this string, consisting of the @a len + characters starting at index @a pos. + @param pos substring's first position relative to the string + @param len length of substring + + If @a pos is negative, starts that far from the end of the string. If @a + len is negative, leaves that many characters off the end of the string. + If @a pos and @a len specify a substring that is partly outside the + string, only the part within the string is returned. If the substring is + beyond either end of the string, returns an empty string (but this + should be considered a programming error; a future version may generate + a warning for this case). + + @note String::substring() is intended to behave like Perl's substr(). */ +String +String::substring(int pos, int len) const +{ + if (pos < 0) + pos += _r.length; + + int pos2; + if (len < 0) + pos2 = _r.length + len; + else if (pos >= 0 && len >= _r.length) // avoid integer overflow + pos2 = _r.length; + else + pos2 = pos + len; + + if (pos < 0) + pos = 0; + if (pos2 > _r.length) + pos2 = _r.length; + + if (pos >= pos2) + return String(); + else + return String(_r.data + pos, pos2 - pos, _r.memo); +} + +int +String::find_left(char c, int start) const +{ + if (start < 0) + start = 0; + for (int i = start; i < _r.length; i++) + if (_r.data[i] == c) + return i; + return -1; +} + +int +String::find_left(const String &str, int start) const +{ + if (start < 0) + start = 0; + int max_pos = length() - str.length(); + for (int i = start; i <= max_pos; ++i) + if (memcmp(_r.data + i, str.data(), str.length()) == 0) + return i; + return -1; +} + +int +String::find_right(char c, int start) const +{ + if (start >= _r.length) + start = _r.length - 1; + for (int i = start; i >= 0; i--) + if (_r.data[i] == c) + return i; + return -1; +} + +static String +hard_lower(const String &s, int pos) +{ + String new_s(s.data(), s.length()); + char *x = const_cast<char *>(new_s.data()); // know it's mutable + int len = s.length(); + for (; pos < len; pos++) + x[pos] = tolower((unsigned char) x[pos]); + return new_s; +} + +/** @brief Return a lowercased version of this string. + + Translates the ASCII characters 'A' through 'Z' into their lowercase + equivalents. */ +String +String::lower() const +{ + // avoid copies + if (!out_of_memory()) + for (int i = 0; i < _r.length; i++) + if (_r.data[i] >= 'A' && _r.data[i] <= 'Z') + return hard_lower(*this, i); + return *this; +} + +static String +hard_upper(const String &s, int pos) +{ + String new_s(s.data(), s.length()); + char *x = const_cast<char *>(new_s.data()); // know it's mutable + int len = s.length(); + for (; pos < len; pos++) + x[pos] = toupper((unsigned char) x[pos]); + return new_s; +} + +/** @brief Return an uppercased version of this string. + + Translates the ASCII characters 'a' through 'z' into their uppercase + equivalents. */ +String +String::upper() const +{ + // avoid copies + for (int i = 0; i < _r.length; i++) + if (_r.data[i] >= 'a' && _r.data[i] <= 'z') + return hard_upper(*this, i); + return *this; +} + +static String +hard_printable(const String &s, int pos, int type) +{ + StringAccum sa(s.length() * 2); + sa.append(s.data(), pos); + const unsigned char *x = reinterpret_cast<const unsigned char *>(s.data()); + int len = s.length(); + for (; pos < len; pos++) { + if (x[pos] >= 32 && x[pos] < 127) + sa << x[pos]; + else if (x[pos] < 32 && type != 1) + sa << '^' << (unsigned char)(x[pos] + 64); + else if (char *buf = sa.extend(4, 1)) + sprintf(buf, "\\%03o", x[pos]); + } + return sa.take_string(); +} + +/** @brief Return a "printable" version of this string. + @param type quoting type + + The default quoting type (0) translates control characters 0-31 into + "control" sequences, such as "^@" for the null character, and characters + 127-255 into octal escape sequences, such as "\377" for 255. Quoting + type 1 translates all characters outside of 32-126 into octal escape + sequences. */ +String +String::printable(int type) const +{ + // avoid copies + if (!out_of_memory()) + for (int i = 0; i < _r.length; i++) + if (_r.data[i] < 32 || _r.data[i] > 126) + return hard_printable(*this, i, type); + return *this; +} + +hashcode_t +String::hashcode(const char *begin, const char *end) +{ + if (end <= begin) + return 0; + + uint32_t hash = end - begin; + int rem = hash & 3; + end -= rem; + uint32_t last16; + +#if !HAVE_INDIFFERENT_ALIGNMENT + if (!(reinterpret_cast<uintptr_t>(begin) & 1)) { +#endif +#define get16(p) (*reinterpret_cast<const uint16_t *>((p))) + for (; begin != end; begin += 4) { + hash += get16(begin); + uint32_t tmp = (get16(begin + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + hash += hash >> 11; + } + if (rem >= 2) { + last16 = get16(begin); + goto rem2; + } +#undef get16 +#if !HAVE_INDIFFERENT_ALIGNMENT + } else { +# if WORDS_BIGENDIAN +# define get16(p) (((unsigned char) (p)[0] << 8) + (unsigned char) (p)[1]) +# elif WORDS_LITTLEENDIAN +# define get16(p) ((unsigned char) (p)[0] + ((unsigned char) (p)[1] << 8)) +# else +# error "unknown byte order" +# endif + // should be exactly the same as the code above + for (; begin != end; begin += 4) { + hash += get16(begin); + uint32_t tmp = (get16(begin + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + hash += hash >> 11; + } + if (rem >= 2) { + last16 = get16(begin); + goto rem2; + } +# undef get16 + } +#endif + + /* Handle end cases */ + if (0) { // weird organization avoids uninitialized + rem2: // variable warnings + if (rem == 3) { + hash += last16; + hash ^= hash << 16; + hash ^= ((unsigned char) begin[2]) << 18; + hash += hash >> 11; + } else { + hash += last16; + hash ^= hash << 11; + hash += hash >> 17; + } + } else if (rem == 1) { + hash += (unsigned char) *begin; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +#if 0 +// 11.Apr.2008 -- This old hash function was swapped out in favor of +// SuperFastHash, above. +hashcode_t +String::hashcode() const +{ + int l = length(); + const char *d = data(); + if (!l) + return 0; + else if (l == 1) + return d[0] | (d[0] << 8); + else if (l < 4) + return d[0] + (d[1] << 3) + (l << 12); + else + return d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24) + + (l << 12) + (d[l-1] << 10); +} +#endif + +bool +String::equals(const char *s, int len) const +{ + // It'd be nice to make "out-of-memory" strings compare unequal to + // anything, even themselves, but this would be a bad idea for Strings + // used as (for example) keys in hashtables. Instead, "out-of-memory" + // strings compare unequal to other null strings, but equal to each other. + if (len < 0) + len = strlen(s); + if (_r.length != len) + return false; + else if (_r.data == s) + return true; + else if (len == 0) + return (s != &oom_data && _r.data != &oom_data); + else + return memcmp(_r.data, s, len) == 0; +} + +bool +String::starts_with(const char *s, int len) const +{ + // See note on equals() re: "out-of-memory" strings. + if (len < 0) + len = strlen(s); + if (_r.length < len) + return false; + else if (_r.data == s) + return true; + else if (len == 0) + return (s != &oom_data && _r.data != &oom_data); + else + return memcmp(_r.data, s, len) == 0; +} + +int +String::compare(const char *s, int len) const +{ + if (len < 0) + len = strlen(s); + if (_r.data == s) + return _r.length - len; + else if (_r.data == &oom_data) + return 1; + else if (s == &oom_data) + return -1; + else if (_r.length == len) + return memcmp(_r.data, s, len); + else if (_r.length < len) { + int v = memcmp(_r.data, s, _r.length); + return (v ? v : -1); + } else { + int v = memcmp(_r.data, s, len); + return (v ? v : 1); + } +} + +void +String::align(int n) +{ + int offset = reinterpret_cast<uintptr_t>(_r.data) % n; + if (offset) { + String s; + s.append_uninitialized(_r.length + n + 1); + offset = reinterpret_cast<uintptr_t>(s._r.data) % n; + memcpy((char *)s._r.data + n - offset, _r.data, _r.length); + s._r.data += n - offset; + s._r.length = _r.length; + *this = s; + } +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/strtonum.c b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/strtonum.c new file mode 100644 index 00000000000..36898c5a7ad --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/strtonum.c @@ -0,0 +1,31 @@ +/* -*- related-file-name: "../include/lcdf/strtonum.h" -*- */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/strtonum.h> +#include <stdlib.h> +#if HAVE_BROKEN_STRTOD +# define strtod good_strtod +#endif +#ifdef __cplusplus +extern "C" { +#endif + +/* A faster strtod which only calls the real strtod if the string has a + fractional part. */ + +double +strtonumber(const char *f, char **endf) +{ + long v = strtol((char *)f, endf, 10); + + /* handle any possible decimal part */ + if (**endf == '.' || **endf == 'E' || **endf == 'e') + return strtod((char *)f, endf); + else + return v; +} + +#ifdef __cplusplus +} +#endif diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/transform.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/transform.cc new file mode 100644 index 00000000000..5eb0ff58728 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/transform.cc @@ -0,0 +1,167 @@ +// -*- related-file-name: "../include/lcdf/transform.hh" -*- + +/* transform.{cc,hh} -- planar affine transformations + * + * Copyright (c) 2000-2012 Eddie Kohler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/transform.hh> +#include <lcdf/straccum.hh> +#include <math.h> + +Transform::Transform() +{ + _m[0] = _m[3] = 1; + _m[1] = _m[2] = _m[4] = _m[5] = 0; + _null = true; +} + +Transform::Transform(const double m[6]) +{ + _m[0] = m[0]; + _m[1] = m[1]; + _m[2] = m[2]; + _m[3] = m[3]; + _m[4] = m[4]; + _m[5] = m[5]; + check_null(0); +} + +Transform::Transform(double m0, double m1, double m2, + double m3, double m4, double m5) +{ + _m[0] = m0; + _m[1] = m1; + _m[2] = m2; + _m[3] = m3; + _m[4] = m4; + _m[5] = m5; + check_null(0); +} + +void +Transform::check_null(double tolerance) +{ + _null = (fabs(_m[0] - 1) < tolerance && fabs(_m[1]) < tolerance + && fabs(_m[2]) < tolerance && fabs(_m[3] - 1) < tolerance + && fabs(_m[4]) < tolerance && fabs(_m[5]) < tolerance); +} + + +void +Transform::scale(double x, double y) +{ + _m[0] *= x; + _m[1] *= x; + _m[2] *= y; + _m[3] *= y; + + if (x != 1 || y != 1) + _null = false; +} + +void +Transform::rotate(double r) +{ + double c = cos(r); + double s = sin(r); + + double a = _m[0], b = _m[2]; + _m[0] = a*c + b*s; + _m[2] = b*c - a*s; + + a = _m[1], b = _m[3]; + _m[1] = a*c + b*s; + _m[3] = b*c - a*s; + + if (r != 0) + _null = false; +} + +void +Transform::translate(double x, double y) +{ + _m[4] += _m[0]*x + _m[2]*y; + _m[5] += _m[1]*x + _m[3]*y; + + if (x != 0 || y != 0) + _null = false; +} + +void +Transform::shear(double s) +{ + *this *= Transform(1, 0, s, 1, 0, 0); +} + +Transform +Transform::transformed(const Transform &t) const +{ + return Transform(_m[0] * t._m[0] + _m[2] * t._m[1], + _m[1] * t._m[0] + _m[3] * t._m[1], + _m[0] * t._m[2] + _m[2] * t._m[3], + _m[1] * t._m[2] + _m[3] * t._m[3], + _m[0] * t._m[4] + _m[2] * t._m[5] + _m[4], + _m[1] * t._m[4] + _m[3] * t._m[5] + _m[5]); +} + + +void +Transform::real_apply_to(Point &p) const +{ + double x = p.x; + p.x = x*_m[0] + p.y*_m[2] + _m[4]; + p.y = x*_m[1] + p.y*_m[3] + _m[5]; +} + +Point +Transform::real_apply(const Point &p) const +{ + return Point(p.x*_m[0] + p.y*_m[2] + _m[4], + p.x*_m[1] + p.y*_m[3] + _m[5]); +} + +Bezier & +operator*=(Bezier &b, const Transform &t) +{ + if (!t.null()) { + b.mpoint(0) *= t; + b.mpoint(1) *= t; + b.mpoint(2) *= t; + b.mpoint(3) *= t; + } + return b; +} + +Bezier +operator*(const Bezier &b, const Transform &t) +{ + return (t.null() + ? b + : Bezier(b.point(0) * t, b.point(1) * t, b.point(2) * t, b.point(3) * t)); +} + +String +Transform::unparse() const +{ + StringAccum sa; + sa << '['; + for (int i = 0; i < 6; i++) { + if (i) + sa << ',' << ' '; + sa << _m[i]; + } + sa << ']'; + return sa.take_string(); +} diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/vectorv.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/vectorv.cc new file mode 100644 index 00000000000..f5f12b52c90 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/vectorv.cc @@ -0,0 +1,110 @@ +/* + * vectorv.cc -- template specialization for Vector<void*> + * Eddie Kohler + * + * Copyright (c) 1999-2006 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/vector.hh> +#include <string.h> + +Vector<void*>::Vector(const Vector<void*> &o) + : _l(0), _n(0), _capacity(0) +{ + *this = o; +} + +Vector<void*>::~Vector() +{ + delete[] _l; +} + +Vector<void*> & +Vector<void*>::operator=(const Vector<void*> &o) +{ + if (&o != this) { + _n = 0; + if (reserve(o._n)) { + _n = o._n; + memcpy(_l, o._l, sizeof(void *) * _n); + } + } + return *this; +} + +Vector<void*> & +Vector<void*>::assign(int n, void *e) +{ + _n = 0; + resize(n, e); + return *this; +} + +bool +Vector<void*>::reserve(int want) +{ + if (want < 0) + want = (_capacity > 0 ? _capacity * 2 : 4); + if (want <= _capacity) + return true; + + void **new_l = new void*[want]; + if (!new_l) + return false; + + memcpy(new_l, _l, sizeof(void*) * _n); + delete[] _l; + + _l = new_l; + _capacity = want; + return true; +} + +Vector<void*>::iterator +Vector<void*>::erase(iterator a, iterator b) +{ + if (b > a) { + assert(a >= begin() && b <= end()); + memmove(a, b, (end() - b) * sizeof(void*)); + _n -= b - a; + return a; + } else + return b; +} + +void +Vector<void*>::resize(int nn, void *e) +{ + if (nn <= _capacity || reserve(nn)) { + for (int i = _n; i < nn; i++) + _l[i] = e; + _n = nn; + } +} + +void +Vector<void*>::swap(Vector<void*>& o) +{ + void **l = _l; + int n = _n; + int cap = _capacity; + _l = o._l; + _n = o._n; + _capacity = o._capacity; + o._l = l; + o._n = n; + o._capacity = cap; +} |