From 92dc14958192b4ed230b3fe08ff351a78c2c595b Mon Sep 17 00:00:00 2001 From: "Troy D. Hanson" Date: Wed, 12 Oct 2011 23:23:05 -0400 Subject: [PATCH] initial import --- LICENSE | 31 + Makefile.am | 14 + Makefile.in | 820 +++ README | 5 + TODO | 9 + aclocal.m4 | 952 +++ bootstrap | 10 + config.status | 1181 ++++ config/config.h | 29 + config/config.h.in | 28 + config/depcomp | 630 ++ config/install-sh | 520 ++ config/missing | 376 ++ config/python.m4 | 327 ++ config/stamp-h1 | 1 + configure | 5321 +++++++++++++++++ configure.ac | 24 + kvperl/.gitignore | 5 + kvperl/Changes | 6 + kvperl/KVSpool.xs | 252 + kvperl/MANIFEST | 10 + kvperl/Makefile | 3 + kvperl/Makefile.PL | 41 + kvperl/Makefile.gen.old | 944 +++ kvperl/README | 40 + kvperl/const-c.inc | 65 + kvperl/const-xs.inc | 90 + kvperl/fallback/const-c.inc | 65 + kvperl/fallback/const-xs.inc | 90 + kvperl/lib/KVSpool.pm | 159 + kvperl/ppport.h | 7063 +++++++++++++++++++++++ kvperl/t/KVSpool.t | 30 + kvperl/test.pl | 34 + kvpy/Makefile | 16 + kvpy/build.py | 12 + kvpy/kvpymodule.c | 202 + kvpy/utils/README | 5 + kvpy/utils/read.py | 11 + kvpy/utils/read_all.py | 12 + kvpy/utils/runtest.sh | 12 + kvpy/utils/speed.py | 28 + kvpy/utils/write.py | 10 + kvspool.c | 136 + kvspool.h | 69 + kvspool_attrition.c | 121 + kvspool_internal.h | 38 + kvspoolr.c | 449 ++ kvspoolw.c | 405 ++ sysutils/README | 6 + sysutils/logd/.gitignore | 6 + sysutils/logd/Makefile | 31 + sysutils/logd/README | 14 + sysutils/logd/logc.c | 81 + sysutils/logd/logc.h | 9 + sysutils/logd/logd/Makefile | 18 + sysutils/logd/logd/logd.c | 231 + sysutils/logd/logd/logd.h | 8 + sysutils/logd/tests/Makefile | 12 + sysutils/logd/tests/README | 2 + sysutils/logd/tests/test1.c | 7 + sysutils/logd/tests/test2.c | 8 + sysutils/logd/uthash.h | 973 ++++ sysutils/logd/utstring.h | 146 + sysutils/pm/.gitignore | 6 + sysutils/pm/Makefile | 25 + sysutils/pm/cfg.y | 41 + sysutils/pm/job.c | 393 ++ sysutils/pm/job.h | 61 + sysutils/pm/lemon/Makefile | 9 + sysutils/pm/lemon/lemon.c | 4889 ++++++++++++++++ sysutils/pm/lemon/lemon.txt | 433 ++ sysutils/pm/lemon/lempar.c | 842 +++ sysutils/pm/pm.c | 245 + sysutils/pm/test/bad.txt | 8 + sysutils/pm/test/dm.conf | 16 + sysutils/pm/test/dup.txt | 8 + sysutils/pm/test/env.txt | 7 + sysutils/pm/test/job.txt | 7 + sysutils/pm/test/job2.txt | 10 + sysutils/pm/test/jobs.txt | 19 + sysutils/pm/test/jobs_nonl.txt | 26 + sysutils/pm/test/norespawn.txt | 4 + sysutils/pm/test/sleep.txt | 31 + sysutils/pm/test/usr.txt | 9 + sysutils/pm/tok.c | 91 + sysutils/pm/upstart/README | 7 + sysutils/pm/upstart/pm.conf | 20 + sysutils/pm/utarray.h | 224 + sysutils/pm/utstring.h | 137 + sysutils/qcp/.gitignore | 2 + sysutils/qcp/Makefile | 11 + sysutils/qcp/qcp.c | 150 + sysutils/qcp/qcps.c | 120 + sysutils/ramdisk/.gitignore | 1 + sysutils/ramdisk/Makefile | 11 + sysutils/ramdisk/ramdisk.c | 159 + sysutils/ramdisk/utarray.h | 226 + sysutils/sized/.gitignore | 1 + sysutils/sized/Makefile | 15 + sysutils/sized/sized.c | 306 + sysutils/sized/utarray.h | 224 + sysutils/sized/utstring.h | 138 + tests/.gitignore | 2 + tests/Makefile | 27 + tests/README | 15 + tests/do_tests | 21 + tests/test1.ans | 3 + tests/test1.c | 21 + tests/test10.ans | 18 + tests/test10.c | 81 + tests/test11.ans | 5 + tests/test11.c | 52 + tests/test12.ans | 13 + tests/test12.c | 73 + tests/test13.ans | 11 + tests/test13.c | 91 + tests/test14.ans | 13 + tests/test14.c | 77 + tests/test15.c | 35 + tests/test2.ans | 3 + tests/test2.c | 22 + tests/test3.ans | 2 + tests/test3.c | 32 + tests/test4.ans | 5 + tests/test4.c | 40 + tests/test5.ans | 7 + tests/test5.c | 45 + tests/test6.ans | 49 + tests/test6.c | 50 + tests/test7.ans | 16 + tests/test7.c | 66 + tests/test8.ans | 3 + tests/test8.c | 23 + tests/test9.ans | 24 + tests/test9.c | 81 + tests/utils.c | 82 + tests/utils.h | 3 + tpl.c | 2479 ++++++++ tpl.h | 133 + utarray.h | 232 + uthash.h | 904 +++ utils/.deps/kvsp-export.Po | 197 + utils/.deps/kvsp-import.Po | 174 + utils/.deps/kvsp-mod.Po | 122 + utils/.deps/kvsp-prune.Po | 118 + utils/.deps/kvsp-pub.Po | 179 + utils/.deps/kvsp-reset.Po | 117 + utils/.deps/kvsp-size.Po | 136 + utils/.deps/kvsp-speed.Po | 119 + utils/.deps/kvsp-split.Po | 122 + utils/.deps/kvsp-spr.Po | 123 + utils/.deps/kvsp-spw.Po | 117 + utils/.deps/kvsp-status.Po | 156 + utils/.deps/kvsp-sub.Po | 145 + utils/.deps/kvsp-tee.Po | 134 + utils/.gitignore | 11 + utils/Makefile.am | 25 + utils/Makefile.in | 566 ++ utils/kvsp-export.c | 168 + utils/kvsp-import.c | 163 + utils/kvsp-mod.c | 100 + utils/kvsp-pub.c | 287 + utils/kvsp-reset.c | 32 + utils/kvsp-size.c | 71 + utils/kvsp-speed.c | 74 + utils/kvsp-split.c | 104 + utils/kvsp-spr.c | 57 + utils/kvsp-spw.c | 62 + utils/kvsp-status.c | 78 + utils/kvsp-sub.c | 118 + utils/kvsp-tee.c | 139 + utils/ts/Makefile | 12 + utils/ts/tests/Makefile | 27 + utils/ts/tests/do_tests | 21 + utils/ts/tests/test1.ans | 55 + utils/ts/tests/test1.c | 22 + utils/ts/tests/test2.ans | 55 + utils/ts/tests/test2.c | 22 + utils/ts/tests/test3.ans | 55 + utils/ts/tests/test3.c | 23 + utils/ts/tests/test4.ans | 55 + utils/ts/tests/test4.c | 30 + utils/ts/tests/test5.ans | 55 + utils/ts/tests/test5.c | 23 + utils/ts/ts.c | 77 + utils/ts/ts.h | 30 + utils/ts/ts.o | Bin 0 -> 9080 bytes utstring.h | 148 + zmq_app/Makefile | 27 + zmq_app/README | 13 + zmq_app/example/Makefile | 21 + zmq_app/example/kvzuri.c | 275 + zmq_app/example/kvzuri.h | 53 + zmq_app/example/kvzuri_cmds.c | 111 + zmq_app/example/tracker.c | 126 + zmq_app/example/tracker.h | 31 + zmq_app/example/tracker_tests/Makefile | 28 + zmq_app/example/tracker_tests/do_tests | 21 + zmq_app/example/tracker_tests/test1.ans | 0 zmq_app/example/tracker_tests/test1.c | 8 + zmq_app/example/tracker_tests/test2.ans | 51 + zmq_app/example/tracker_tests/test2.c | 32 + zmq_app/example/tracker_tests/test3.ans | 68 + zmq_app/example/tracker_tests/test3.c | 37 + zmq_app/example/tracker_tests/test4.ans | 51 + zmq_app/example/tracker_tests/test4.c | 34 + zmq_app/kvz.c | 169 + zmq_app/kvz.h | 27 + zmq_app/kvz_cmds.c | 45 + zmq_app/ts.c | 86 + zmq_app/ts.h | 31 + zmq_app/ts_tests/Makefile | 27 + zmq_app/ts_tests/do_tests | 21 + zmq_app/ts_tests/test1.ans | 55 + zmq_app/ts_tests/test1.c | 22 + zmq_app/ts_tests/test2.ans | 55 + zmq_app/ts_tests/test2.c | 22 + zmq_app/ts_tests/test3.ans | 55 + zmq_app/ts_tests/test3.c | 23 + zmq_app/ts_tests/test4.ans | 55 + zmq_app/ts_tests/test4.c | 30 + zmq_app/ts_tests/test5.ans | 55 + zmq_app/ts_tests/test5.c | 23 + zmq_app/ts_tests/test6.ans | 33 + zmq_app/ts_tests/test6.c | 19 + zmq_app/ts_tests/test7.ans | 44 + zmq_app/ts_tests/test7.c | 21 + zmq_app/zcon.c | 177 + zmq_app/zcontrol.c | 173 + zmq_app/zcontrol.h | 30 + 230 files changed, 43053 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 TODO create mode 100644 aclocal.m4 create mode 100755 bootstrap create mode 100755 config.status create mode 100644 config/config.h create mode 100644 config/config.h.in create mode 100755 config/depcomp create mode 100755 config/install-sh create mode 100755 config/missing create mode 100644 config/python.m4 create mode 100644 config/stamp-h1 create mode 100755 configure create mode 100644 configure.ac create mode 100644 kvperl/.gitignore create mode 100644 kvperl/Changes create mode 100644 kvperl/KVSpool.xs create mode 100644 kvperl/MANIFEST create mode 100644 kvperl/Makefile create mode 100644 kvperl/Makefile.PL create mode 100644 kvperl/Makefile.gen.old create mode 100644 kvperl/README create mode 100644 kvperl/const-c.inc create mode 100644 kvperl/const-xs.inc create mode 100644 kvperl/fallback/const-c.inc create mode 100644 kvperl/fallback/const-xs.inc create mode 100644 kvperl/lib/KVSpool.pm create mode 100644 kvperl/ppport.h create mode 100644 kvperl/t/KVSpool.t create mode 100644 kvperl/test.pl create mode 100644 kvpy/Makefile create mode 100644 kvpy/build.py create mode 100644 kvpy/kvpymodule.c create mode 100644 kvpy/utils/README create mode 100755 kvpy/utils/read.py create mode 100755 kvpy/utils/read_all.py create mode 100755 kvpy/utils/runtest.sh create mode 100755 kvpy/utils/speed.py create mode 100755 kvpy/utils/write.py create mode 100644 kvspool.c create mode 100644 kvspool.h create mode 100644 kvspool_attrition.c create mode 100644 kvspool_internal.h create mode 100644 kvspoolr.c create mode 100644 kvspoolw.c create mode 100644 sysutils/README create mode 100644 sysutils/logd/.gitignore create mode 100644 sysutils/logd/Makefile create mode 100644 sysutils/logd/README create mode 100644 sysutils/logd/logc.c create mode 100644 sysutils/logd/logc.h create mode 100644 sysutils/logd/logd/Makefile create mode 100644 sysutils/logd/logd/logd.c create mode 100644 sysutils/logd/logd/logd.h create mode 100644 sysutils/logd/tests/Makefile create mode 100644 sysutils/logd/tests/README create mode 100644 sysutils/logd/tests/test1.c create mode 100644 sysutils/logd/tests/test2.c create mode 100644 sysutils/logd/uthash.h create mode 100644 sysutils/logd/utstring.h create mode 100644 sysutils/pm/.gitignore create mode 100644 sysutils/pm/Makefile create mode 100644 sysutils/pm/cfg.y create mode 100644 sysutils/pm/job.c create mode 100644 sysutils/pm/job.h create mode 100644 sysutils/pm/lemon/Makefile create mode 100644 sysutils/pm/lemon/lemon.c create mode 100644 sysutils/pm/lemon/lemon.txt create mode 100644 sysutils/pm/lemon/lempar.c create mode 100644 sysutils/pm/pm.c create mode 100644 sysutils/pm/test/bad.txt create mode 100644 sysutils/pm/test/dm.conf create mode 100644 sysutils/pm/test/dup.txt create mode 100644 sysutils/pm/test/env.txt create mode 100644 sysutils/pm/test/job.txt create mode 100644 sysutils/pm/test/job2.txt create mode 100644 sysutils/pm/test/jobs.txt create mode 100644 sysutils/pm/test/jobs_nonl.txt create mode 100644 sysutils/pm/test/norespawn.txt create mode 100644 sysutils/pm/test/sleep.txt create mode 100644 sysutils/pm/test/usr.txt create mode 100644 sysutils/pm/tok.c create mode 100644 sysutils/pm/upstart/README create mode 100644 sysutils/pm/upstart/pm.conf create mode 100644 sysutils/pm/utarray.h create mode 100644 sysutils/pm/utstring.h create mode 100644 sysutils/qcp/.gitignore create mode 100644 sysutils/qcp/Makefile create mode 100644 sysutils/qcp/qcp.c create mode 100644 sysutils/qcp/qcps.c create mode 100644 sysutils/ramdisk/.gitignore create mode 100644 sysutils/ramdisk/Makefile create mode 100644 sysutils/ramdisk/ramdisk.c create mode 100644 sysutils/ramdisk/utarray.h create mode 100644 sysutils/sized/.gitignore create mode 100644 sysutils/sized/Makefile create mode 100644 sysutils/sized/sized.c create mode 100644 sysutils/sized/utarray.h create mode 100644 sysutils/sized/utstring.h create mode 100644 tests/.gitignore create mode 100644 tests/Makefile create mode 100644 tests/README create mode 100755 tests/do_tests create mode 100644 tests/test1.ans create mode 100644 tests/test1.c create mode 100644 tests/test10.ans create mode 100644 tests/test10.c create mode 100644 tests/test11.ans create mode 100644 tests/test11.c create mode 100644 tests/test12.ans create mode 100644 tests/test12.c create mode 100644 tests/test13.ans create mode 100644 tests/test13.c create mode 100644 tests/test14.ans create mode 100644 tests/test14.c create mode 100644 tests/test15.c create mode 100644 tests/test2.ans create mode 100644 tests/test2.c create mode 100644 tests/test3.ans create mode 100644 tests/test3.c create mode 100644 tests/test4.ans create mode 100644 tests/test4.c create mode 100644 tests/test5.ans create mode 100644 tests/test5.c create mode 100644 tests/test6.ans create mode 100644 tests/test6.c create mode 100644 tests/test7.ans create mode 100644 tests/test7.c create mode 100644 tests/test8.ans create mode 100644 tests/test8.c create mode 100644 tests/test9.ans create mode 100644 tests/test9.c create mode 100644 tests/utils.c create mode 100644 tests/utils.h create mode 100644 tpl.c create mode 100644 tpl.h create mode 100644 utarray.h create mode 100644 uthash.h create mode 100644 utils/.deps/kvsp-export.Po create mode 100644 utils/.deps/kvsp-import.Po create mode 100644 utils/.deps/kvsp-mod.Po create mode 100644 utils/.deps/kvsp-prune.Po create mode 100644 utils/.deps/kvsp-pub.Po create mode 100644 utils/.deps/kvsp-reset.Po create mode 100644 utils/.deps/kvsp-size.Po create mode 100644 utils/.deps/kvsp-speed.Po create mode 100644 utils/.deps/kvsp-split.Po create mode 100644 utils/.deps/kvsp-spr.Po create mode 100644 utils/.deps/kvsp-spw.Po create mode 100644 utils/.deps/kvsp-status.Po create mode 100644 utils/.deps/kvsp-sub.Po create mode 100644 utils/.deps/kvsp-tee.Po create mode 100644 utils/.gitignore create mode 100644 utils/Makefile.am create mode 100644 utils/Makefile.in create mode 100644 utils/kvsp-export.c create mode 100644 utils/kvsp-import.c create mode 100644 utils/kvsp-mod.c create mode 100644 utils/kvsp-pub.c create mode 100644 utils/kvsp-reset.c create mode 100644 utils/kvsp-size.c create mode 100644 utils/kvsp-speed.c create mode 100644 utils/kvsp-split.c create mode 100644 utils/kvsp-spr.c create mode 100644 utils/kvsp-spw.c create mode 100644 utils/kvsp-status.c create mode 100644 utils/kvsp-sub.c create mode 100644 utils/kvsp-tee.c create mode 100644 utils/ts/Makefile create mode 100644 utils/ts/tests/Makefile create mode 100755 utils/ts/tests/do_tests create mode 100644 utils/ts/tests/test1.ans create mode 100644 utils/ts/tests/test1.c create mode 100644 utils/ts/tests/test2.ans create mode 100644 utils/ts/tests/test2.c create mode 100644 utils/ts/tests/test3.ans create mode 100644 utils/ts/tests/test3.c create mode 100644 utils/ts/tests/test4.ans create mode 100644 utils/ts/tests/test4.c create mode 100644 utils/ts/tests/test5.ans create mode 100644 utils/ts/tests/test5.c create mode 100644 utils/ts/ts.c create mode 100644 utils/ts/ts.h create mode 100644 utils/ts/ts.o create mode 100644 utstring.h create mode 100644 zmq_app/Makefile create mode 100644 zmq_app/README create mode 100644 zmq_app/example/Makefile create mode 100644 zmq_app/example/kvzuri.c create mode 100644 zmq_app/example/kvzuri.h create mode 100644 zmq_app/example/kvzuri_cmds.c create mode 100644 zmq_app/example/tracker.c create mode 100644 zmq_app/example/tracker.h create mode 100644 zmq_app/example/tracker_tests/Makefile create mode 100755 zmq_app/example/tracker_tests/do_tests create mode 100644 zmq_app/example/tracker_tests/test1.ans create mode 100644 zmq_app/example/tracker_tests/test1.c create mode 100644 zmq_app/example/tracker_tests/test2.ans create mode 100644 zmq_app/example/tracker_tests/test2.c create mode 100644 zmq_app/example/tracker_tests/test3.ans create mode 100644 zmq_app/example/tracker_tests/test3.c create mode 100644 zmq_app/example/tracker_tests/test4.ans create mode 100644 zmq_app/example/tracker_tests/test4.c create mode 100644 zmq_app/kvz.c create mode 100644 zmq_app/kvz.h create mode 100644 zmq_app/kvz_cmds.c create mode 100644 zmq_app/ts.c create mode 100644 zmq_app/ts.h create mode 100644 zmq_app/ts_tests/Makefile create mode 100755 zmq_app/ts_tests/do_tests create mode 100644 zmq_app/ts_tests/test1.ans create mode 100644 zmq_app/ts_tests/test1.c create mode 100644 zmq_app/ts_tests/test2.ans create mode 100644 zmq_app/ts_tests/test2.c create mode 100644 zmq_app/ts_tests/test3.ans create mode 100644 zmq_app/ts_tests/test3.c create mode 100644 zmq_app/ts_tests/test4.ans create mode 100644 zmq_app/ts_tests/test4.c create mode 100644 zmq_app/ts_tests/test5.ans create mode 100644 zmq_app/ts_tests/test5.c create mode 100644 zmq_app/ts_tests/test6.ans create mode 100644 zmq_app/ts_tests/test6.c create mode 100644 zmq_app/ts_tests/test7.ans create mode 100644 zmq_app/ts_tests/test7.c create mode 100644 zmq_app/zcon.c create mode 100644 zmq_app/zcontrol.c create mode 100644 zmq_app/zcontrol.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f2abe0d --- /dev/null +++ b/LICENSE @@ -0,0 +1,31 @@ +LICENSE AND DISCLAIMER + +Copyright (c) 2011 The Johns Hopkins University/Applied Physics Laboratory + +This software was developed at The Johns Hopkins University/Applied Physics +Laboratory (“JHU/APL”) that is the author thereof under the “work made for +hire” provisions of the copyright law. Permission is hereby granted, free of +charge, to any person obtaining a copy of this software and associated +documentation (the “Software”), to use the Software without restriction, +including without limitation the rights to copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +others to do so, subject to the following conditions: + + 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall be + included in all copies of the Software, including copies of substantial + portions of the Software; + + 2. JHU/APL assumes no obligation to provide support of any kind with regard + to the Software. This includes no obligation to provide assistance in using + the Software nor to provide updated versions of the Software; and + + 3. THE SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED AS IS AND WITHOUT ANY + EXPRESS OR IMPLIED WARRANTIES WHATSOEVER. ALL WARRANTIES INCLUDING, BUT NOT + LIMITED TO, PERFORMANCE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + AND NONINFRINGEMENT ARE HEREBY DISCLAIMED. USERS ASSUME THE ENTIRE RISK AND + LIABILITY OF USING THE SOFTWARE. USERS ARE ADVISED TO TEST THE SOFTWARE + THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE JOHNS HOPKINS + UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, WITHOUT + LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + SOFTWARE.” diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..77580dd --- /dev/null +++ b/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = -fPIC +lib_LIBRARIES = libkvspool.a +libkvspool_a_SOURCES = kvspool.c kvspoolw.c kvspoolr.c kvspool_attrition.c tpl.c +include_HEADERS = kvspool.h + +SUBDIRS = . utils + +if HAVE_PYTHON +SUBDIRS += kvpy +endif + +if HAVE_PERL +SUBDIRS += kvperl +endif diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..6723c38 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,820 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@ +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 = : +@HAVE_PYTHON_TRUE@am__append_1 = kvpy +@HAVE_PERL_TRUE@am__append_2 = kvperl +subdir = . +DIST_COMMON = $(am__configure_deps) $(include_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/config/config.h.in $(top_srcdir)/configure \ + config/depcomp config/install-sh config/missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/python.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +LIBRARIES = $(lib_LIBRARIES) +AR = ar +ARFLAGS = cru +libkvspool_a_AR = $(AR) $(ARFLAGS) +libkvspool_a_LIBADD = +am_libkvspool_a_OBJECTS = kvspool.$(OBJEXT) kvspoolw.$(OBJEXT) \ + kvspoolr.$(OBJEXT) kvspool_attrition.$(OBJEXT) tpl.$(OBJEXT) +libkvspool_a_OBJECTS = $(am_libkvspool_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libkvspool_a_SOURCES) +DIST_SOURCES = $(libkvspool_a_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +HEADERS = $(include_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = . utils kvpy kvperl +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +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@ +PERL = @PERL@ +PYTHON = @PYTHON@ +PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@ +PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@ +PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@ +PYTHON_LDFLAGS = @PYTHON_LDFLAGS@ +PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +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_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +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@ +AM_CFLAGS = -fPIC +lib_LIBRARIES = libkvspool.a +libkvspool_a_SOURCES = kvspool.c kvspoolw.c kvspoolr.c kvspool_attrition.c tpl.c +include_HEADERS = kvspool.h +SUBDIRS = . utils $(am__append_1) $(am__append_2) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config/config.h: config/stamp-h1 + @if test ! -f $@; then \ + rm -f config/stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) config/stamp-h1; \ + else :; fi + +config/stamp-h1: $(top_srcdir)/config/config.h.in $(top_builddir)/config.status + @rm -f config/stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config/config.h +$(top_srcdir)/config/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f config/stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config/config.h config/stamp-h1 +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; } + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + if test -f $$p; then \ + $(am__strip_dir) \ + echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \ + ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libdir)' && rm -f "$$files" )"; \ + cd "$(DESTDIR)$(libdir)" && rm -f $$files + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) +libkvspool.a: $(libkvspool_a_OBJECTS) $(libkvspool_a_DEPENDENCIES) + -rm -f libkvspool.a + $(libkvspool_a_AR) libkvspool.a $(libkvspool_a_OBJECTS) $(libkvspool_a_LIBADD) + $(RANLIB) libkvspool.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvspool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvspool_attrition.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvspoolr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvspoolw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tpl.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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 +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +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-recursive + +clean-am: clean-generic clean-libLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libLIBRARIES ctags ctags-recursive dist dist-all \ + dist-bzip2 dist-gzip dist-lzma dist-shar dist-tarZ dist-xz \ + dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-hdr distclean-tags distcleancheck \ + distdir distuninstallcheck 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-includeHEADERS \ + install-info install-info-am install-libLIBRARIES install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-includeHEADERS uninstall-libLIBRARIES + + +# 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/README b/README index e69de29..c8899db 100644 --- a/README +++ b/README @@ -0,0 +1,5 @@ +kvspool data streaming utilities + +License: See LICENSE file +See also: the TODO file + diff --git a/TODO b/TODO new file mode 100644 index 0000000..3d96a6b --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +1. Establish wiki to replace this document +2. Add missing KVJava +3. Move sysutils to their own repo +4. Add documentation/slides +5. Remove 'base' parameter everywhere +6. Change Python to have object wrapper +7. zcon and zcontrol should be in a ZeroMQ add-on's repo +8. kvsp-import/export should be subsumed by kvsp-pub/sub +9. put libts in external snippets repo diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..aaf5a5d --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,952 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file 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. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],, +[m4_warning([this file was generated for autoconf 2.65. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file 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. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([config/python.m4]) diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..775c601 --- /dev/null +++ b/bootstrap @@ -0,0 +1,10 @@ +#!/bin/sh + +# THIS SCRIPT IS FOR PROJECT MAINTAINER ONLY +# It is executed only to generate "configure" + +set -x +aclocal -I config +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/config.status b/config.status new file mode 100755 index 0000000..dfbc13f --- /dev/null +++ b/config.status @@ -0,0 +1,1181 @@ +#! /bin/bash +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/bash} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by kvspool $as_me 1.0, which was +generated by GNU Autoconf 2.65. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" Makefile utils/Makefile" +config_headers=" config/config.h" +config_commands=" depfiles" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +ac_cs_config="" +ac_cs_version="\ +kvspool config.status 1.0 +configured by ./configure, generated by GNU Autoconf 2.65, + with options \"$ac_cs_config\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/home/thanson/checkouts/cic/linux/kvspool' +srcdir='.' +INSTALL='/usr/bin/install -c' +MKDIR_P='/bin/mkdir -p' +AWK='gawk' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X '/bin/bash' './configure' $ac_configure_extra_args --no-create --no-recursion + shift + $as_echo "running CONFIG_SHELL=/bin/bash $*" >&6 + CONFIG_SHELL='/bin/bash' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +# +# INIT-COMMANDS +# +AMDEP_TRUE="" ac_aux_dir="config" + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config/config.h") CONFIG_HEADERS="$CONFIG_HEADERS config/config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "utils/Makefile") CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +cat >>"$tmp/subs1.awk" <<\_ACAWK && +S["am__EXEEXT_FALSE"]="" +S["am__EXEEXT_TRUE"]="#" +S["LTLIBOBJS"]="" +S["LIBOBJS"]="" +S["HAVE_PERL_FALSE"]="#" +S["HAVE_PERL_TRUE"]="" +S["PERL"]="perl" +S["HAVE_PYTHON_FALSE"]="#" +S["HAVE_PYTHON_TRUE"]="" +S["PYTHON_EXTRA_LDFLAGS"]="-Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions" +S["PYTHON_EXTRA_LIBS"]="-lssl -lcrypto -lssl -lcrypto -L/usr/lib -lz -lpthread -ldl -lutil" +S["PYTHON_SITE_PKG"]="/usr/lib/python2.6/dist-packages" +S["PYTHON_LDFLAGS"]="-L/usr/lib -lpython2.6" +S["PYTHON_CPPFLAGS"]="-I/usr/include/python2.6" +S["PYTHON"]="/usr/bin/python" +S["PYTHON_VERSION"]="" +S["HAVE_ZEROMQ_FALSE"]="#" +S["HAVE_ZEROMQ_TRUE"]="" +S["RANLIB"]="ranlib" +S["am__fastdepCC_FALSE"]="#" +S["am__fastdepCC_TRUE"]="" +S["CCDEPMODE"]="depmode=gcc3" +S["AMDEPBACKSLASH"]="\\" +S["AMDEP_FALSE"]="#" +S["AMDEP_TRUE"]="" +S["am__quote"]="" +S["am__include"]="include" +S["DEPDIR"]=".deps" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="gcc" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-g -O2" +S["CC"]="gcc" +S["am__untar"]="${AMTAR} xf -" +S["am__tar"]="${AMTAR} chof - \"$$tardir\"" +S["AMTAR"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run tar" +S["am__leading_dot"]="." +S["SET_MAKE"]="" +S["AWK"]="gawk" +S["mkdir_p"]="/bin/mkdir -p" +S["MKDIR_P"]="/bin/mkdir -p" +S["INSTALL_STRIP_PROGRAM"]="$(install_sh) -c -s" +S["STRIP"]="" +S["install_sh"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/install-sh" +S["MAKEINFO"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run makeinfo" +S["AUTOHEADER"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run autoheader" +S["AUTOMAKE"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run automake-1.11" +S["AUTOCONF"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run autoconf" +S["ACLOCAL"]="${SHELL} /home/thanson/checkouts/cic/linux/kvspool/config/missing --run aclocal-1.11" +S["VERSION"]="1.0" +S["PACKAGE"]="kvspool" +S["CYGPATH_W"]="echo" +S["am__isrc"]="" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="" +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DHAVE_CONFIG_H" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="troy.hanson@jhuapl.edu" +S["PACKAGE_STRING"]="kvspool 1.0" +S["PACKAGE_VERSION"]="1.0" +S["PACKAGE_TARNAME"]="kvspool" +S["PACKAGE_NAME"]="kvspool" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/bash" +_ACAWK +cat >>"$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +D["PACKAGE_NAME"]=" \"kvspool\"" +D["PACKAGE_TARNAME"]=" \"kvspool\"" +D["PACKAGE_VERSION"]=" \"1.0\"" +D["PACKAGE_STRING"]=" \"kvspool 1.0\"" +D["PACKAGE_BUGREPORT"]=" \"troy.hanson@jhuapl.edu\"" +D["PACKAGE_URL"]=" \"\"" +D["PACKAGE"]=" \"kvspool\"" +D["VERSION"]=" \"1.0\"" +D["HAVE_PYTHON"]=" \"2.6\"" + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { + line = $ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra="/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 diff --git a/config/config.h b/config/config.h new file mode 100644 index 0000000..34a6b7f --- /dev/null +++ b/config/config.h @@ -0,0 +1,29 @@ +/* config/config.h. Generated from config.h.in by configure. */ +/* config/config.h.in. Generated from configure.ac by autoheader. */ + +/* If available, contains the Python version number currently in use. */ +#define HAVE_PYTHON "2.6" + +/* Name of package */ +#define PACKAGE "kvspool" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "troy.hanson@jhuapl.edu" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "kvspool" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "kvspool 1.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "kvspool" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0" + +/* Version number of package */ +#define VERSION "1.0" diff --git a/config/config.h.in b/config/config.h.in new file mode 100644 index 0000000..455db2f --- /dev/null +++ b/config/config.h.in @@ -0,0 +1,28 @@ +/* config/config.h.in. Generated from configure.ac by autoheader. */ + +/* If available, contains the Python version number currently in use. */ +#undef HAVE_PYTHON + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Version number of package */ +#undef VERSION diff --git a/config/depcomp b/config/depcomp new file mode 100755 index 0000000..df8eea7 --- /dev/null +++ b/config/depcomp @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/config/install-sh b/config/install-sh new file mode 100755 index 0000000..6781b98 --- /dev/null +++ b/config/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/config/missing b/config/missing new file mode 100755 index 0000000..28055d2 --- /dev/null +++ b/config/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/config/python.m4 b/config/python.m4 new file mode 100644 index 0000000..8e75b54 --- /dev/null +++ b/config/python.m4 @@ -0,0 +1,327 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON_DEVEL([version]) +# +# DESCRIPTION +# +# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it +# in your configure.ac. +# +# This macro checks for Python and tries to get the include path to +# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS) +# output variables. It also exports $(PYTHON_EXTRA_LIBS) and +# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code. +# +# You can search for some particular version of Python by passing a +# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please +# note that you *have* to pass also an operator along with the version to +# match, and pay special attention to the single quotes surrounding the +# version number. Don't use "PYTHON_VERSION" for this: that environment +# variable is declared as precious and thus reserved for the end-user. +# +# This macro should work for all versions of Python >= 2.1.0. As an end +# user, you can disable the check for the python version by setting the +# PYTHON_NOVERSIONCHECK environment variable to something else than the +# empty string. +# +# If you need to use this macro for an older Python version, please +# contact the authors. We're always open for feedback. +# +# LICENSE +# +# Copyright (c) 2009 Sebastian Huber +# Copyright (c) 2009 Alan W. Irwin +# Copyright (c) 2009 Rafael Laboissiere +# Copyright (c) 2009 Andrew Collier +# Copyright (c) 2009 Matteo Settenvini +# Copyright (c) 2009 Horst Knorr +# +# 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 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 8 + +AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) +AC_DEFUN([AX_PYTHON_DEVEL],[ + # + # Allow the use of a (user set) custom python version + # + AC_ARG_VAR([PYTHON_VERSION],[The installed Python + version to use, for example '2.3'. This string + will be appended to the Python interpreter + canonical name.]) + + AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) + if test -z "$PYTHON"; then + AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) + PYTHON_VERSION="" + fi + + # + # Check for a version of Python >= 2.1.0 + # + AC_MSG_CHECKING([for a version of Python >= '2.1.0']) + ac_supports_python_ver=`$PYTHON -c "import sys; \ + ver = sys.version.split ()[[0]]; \ + print (ver >= '2.1.0')"` + if test "$ac_supports_python_ver" != "True"; then + if test -z "$PYTHON_NOVERSIONCHECK"; then + AC_MSG_RESULT([no]) + AC_MSG_WARN([ +This version of the AC@&t@_PYTHON_DEVEL macro +doesn't work properly with versions of Python before +2.1.0. You may need to re-run configure, setting the +variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, +PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. +Moreover, to disable this check, set PYTHON_NOVERSIONCHECK +to something else than an empty string. +]) + else + AC_MSG_RESULT([skip at user request]) + fi + else + AC_MSG_RESULT([yes]) + fi + + # + # if the macro parameter ``version'' is set, honour it + # + if test -n "$1"; then + AC_MSG_CHECKING([for a version of Python $1]) + ac_supports_python_ver=`$PYTHON -c "import sys; \ + ver = sys.version.split ()[[0]]; \ + print (ver $1)"` + if test "$ac_supports_python_ver" = "True"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([this package requires Python $1. +If you have it installed, but it isn't the default Python +interpreter in your system path, please pass the PYTHON_VERSION +variable to configure. See ``configure --help'' for reference. +]) + PYTHON_VERSION="" + fi + fi + + # + # Check if you have distutils, else fail + # + AC_MSG_CHECKING([for the distutils Python package]) + ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` + if test -z "$ac_distutils_result"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_WARN([cannot import Python module "distutils". +Please check your Python installation. The error was: +$ac_distutils_result]) + PYTHON_VERSION="" + fi + + # + # Check for Python include path + # + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON_CPPFLAGS"; then + python_path=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_inc ());"` + if test -n "${python_path}"; then + python_path="-I$python_path" + fi + PYTHON_CPPFLAGS=$python_path + fi + AC_MSG_RESULT([$PYTHON_CPPFLAGS]) + AC_SUBST([PYTHON_CPPFLAGS]) + + # + # Check for Python library path + # + AC_MSG_CHECKING([for Python library path]) + if test -z "$PYTHON_LDFLAGS"; then + # (makes two attempts to ensure we've got a version number + # from the interpreter) + ac_python_version=`cat<]], + [[Py_Initialize();]]) + ],[pythonexists=yes],[pythonexists=no]) + AC_LANG_POP([C]) + # turn back to default flags + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + + AC_MSG_RESULT([$pythonexists]) + + if test ! "x$pythonexists" = "xyes"; then + AC_MSG_WARN([ + Could not link test program to Python. Maybe the main Python library has been + installed in some non-standard library path. If so, pass it to configure, + via the LDFLAGS environment variable. + Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib" + ============================================================================ + You may have to install the development version of the Python package + for your distribution. The exact name of this package varies among them. + For example, the package may be called "python2.6-dev". For now, we are + skipping the build of the Python kvspool module + ============================================================================ + ]) + PYTHON_VERSION="" + fi + + # + # all done! + # +]) + diff --git a/config/stamp-h1 b/config/stamp-h1 new file mode 100644 index 0000000..22326a7 --- /dev/null +++ b/config/stamp-h1 @@ -0,0 +1 @@ +timestamp for config/config.h diff --git a/configure b/configure new file mode 100755 index 0000000..213f4b8 --- /dev/null +++ b/configure @@ -0,0 +1,5321 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.65 for kvspool 1.0. +# +# Report bugs to . +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: troy.hanson@jhuapl.edu about your system, including any +$0: error possibly output before this message. Then install +$0: a modern shell, or manually run the script under such a +$0: shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='kvspool' +PACKAGE_TARNAME='kvspool' +PACKAGE_VERSION='1.0' +PACKAGE_STRING='kvspool 1.0' +PACKAGE_BUGREPORT='troy.hanson@jhuapl.edu' +PACKAGE_URL='' + +ac_unique_file="kvspool.c" +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +HAVE_PERL_FALSE +HAVE_PERL_TRUE +PERL +HAVE_PYTHON_FALSE +HAVE_PYTHON_TRUE +PYTHON_EXTRA_LDFLAGS +PYTHON_EXTRA_LIBS +PYTHON_SITE_PKG +PYTHON_LDFLAGS +PYTHON_CPPFLAGS +PYTHON +PYTHON_VERSION +HAVE_ZEROMQ_FALSE +HAVE_ZEROMQ_TRUE +RANLIB +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +PYTHON_VERSION' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures kvspool 1.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/kvspool] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of kvspool 1.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + PYTHON_VERSION + The installed Python version to use, for example '2.3'. This + string will be appended to the Python interpreter canonical + name. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +kvspool configure 1.0 +generated by GNU Autoconf 2.65 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by kvspool $as_me 1.0, which was +generated by GNU Autoconf 2.65. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in config "$srcdir"/config; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +ac_config_headers="$ac_config_headers config/config.h" + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='kvspool' + VERSION='1.0' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# is zeromq (0MQ) installed + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for zmq_init in -lzmq" >&5 +$as_echo_n "checking for zmq_init in -lzmq... " >&6; } +if test "${ac_cv_lib_zmq_zmq_init+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lzmq $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char zmq_init (); +int +main () +{ +return zmq_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_zmq_zmq_init=yes +else + ac_cv_lib_zmq_zmq_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_zmq_zmq_init" >&5 +$as_echo "$ac_cv_lib_zmq_zmq_init" >&6; } +if test "x$ac_cv_lib_zmq_zmq_init" = x""yes; then : + if true; then + HAVE_ZEROMQ_TRUE= + HAVE_ZEROMQ_FALSE='#' +else + HAVE_ZEROMQ_TRUE='#' + HAVE_ZEROMQ_FALSE= +fi + +else + if false; then + HAVE_ZEROMQ_TRUE= + HAVE_ZEROMQ_FALSE='#' +else + HAVE_ZEROMQ_TRUE='#' + HAVE_ZEROMQ_FALSE= +fi + +fi + + + + # + # Allow the use of a (user set) custom python version + # + + + # Extract the first word of "python[$PYTHON_VERSION]", so it can be a program name with args. +set dummy python$PYTHON_VERSION; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_PYTHON+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $PYTHON in + [\\/]* | ?:[\\/]*) + ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PYTHON=$ac_cv_path_PYTHON +if test -n "$PYTHON"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 +$as_echo "$PYTHON" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$PYTHON"; then + as_fn_error "Cannot find python$PYTHON_VERSION in your system path" "$LINENO" 5 + PYTHON_VERSION="" + fi + + # + # Check for a version of Python >= 2.1.0 + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a version of Python >= '2.1.0'" >&5 +$as_echo_n "checking for a version of Python >= '2.1.0'... " >&6; } + ac_supports_python_ver=`$PYTHON -c "import sys; \ + ver = sys.version.split ()[0]; \ + print (ver >= '2.1.0')"` + if test "$ac_supports_python_ver" != "True"; then + if test -z "$PYTHON_NOVERSIONCHECK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +This version of the AC_PYTHON_DEVEL macro +doesn't work properly with versions of Python before +2.1.0. You may need to re-run configure, setting the +variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, +PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. +Moreover, to disable this check, set PYTHON_NOVERSIONCHECK +to something else than an empty string. +" >&5 +$as_echo "$as_me: WARNING: +This version of the AC_PYTHON_DEVEL macro +doesn't work properly with versions of Python before +2.1.0. You may need to re-run configure, setting the +variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, +PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. +Moreover, to disable this check, set PYTHON_NOVERSIONCHECK +to something else than an empty string. +" >&2;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: skip at user request" >&5 +$as_echo "skip at user request" >&6; } + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + + # + # if the macro parameter ``version'' is set, honour it + # + if test -n ">= '2.4'"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a version of Python >= '2.4'" >&5 +$as_echo_n "checking for a version of Python >= '2.4'... " >&6; } + ac_supports_python_ver=`$PYTHON -c "import sys; \ + ver = sys.version.split ()[0]; \ + print (ver >= '2.4')"` + if test "$ac_supports_python_ver" = "True"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error "this package requires Python >= '2.4'. +If you have it installed, but it isn't the default Python +interpreter in your system path, please pass the PYTHON_VERSION +variable to configure. See \`\`configure --help'' for reference. +" "$LINENO" 5 + PYTHON_VERSION="" + fi + fi + + # + # Check if you have distutils, else fail + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the distutils Python package" >&5 +$as_echo_n "checking for the distutils Python package... " >&6; } + ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` + if test -z "$ac_distutils_result"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot import Python module \"distutils\". +Please check your Python installation. The error was: +$ac_distutils_result" >&5 +$as_echo "$as_me: WARNING: cannot import Python module \"distutils\". +Please check your Python installation. The error was: +$ac_distutils_result" >&2;} + PYTHON_VERSION="" + fi + + # + # Check for Python include path + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python include path" >&5 +$as_echo_n "checking for Python include path... " >&6; } + if test -z "$PYTHON_CPPFLAGS"; then + python_path=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_inc ());"` + if test -n "${python_path}"; then + python_path="-I$python_path" + fi + PYTHON_CPPFLAGS=$python_path + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_CPPFLAGS" >&5 +$as_echo "$PYTHON_CPPFLAGS" >&6; } + + + # + # Check for Python library path + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python library path" >&5 +$as_echo_n "checking for Python library path... " >&6; } + if test -z "$PYTHON_LDFLAGS"; then + # (makes two attempts to ensure we've got a version number + # from the interpreter) + ac_python_version=`cat<>confdefs.h <<_ACEOF +#define HAVE_PYTHON "$ac_python_version" +_ACEOF + + + # First, the library directory: + ac_python_libdir=`cat<&5 +$as_echo "$PYTHON_LDFLAGS" >&6; } + + + # + # Check for site packages + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python site-packages path" >&5 +$as_echo_n "checking for Python site-packages path... " >&6; } + if test -z "$PYTHON_SITE_PKG"; then + PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_lib(0,0));"` + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_SITE_PKG" >&5 +$as_echo "$PYTHON_SITE_PKG" >&6; } + + + # + # libraries which must be linked in when embedding + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking python extra libraries" >&5 +$as_echo_n "checking python extra libraries... " >&6; } + if test -z "$PYTHON_EXTRA_LIBS"; then + PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print (conf('LOCALMODLIBS') + ' ' + conf('LIBS'))"` + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_EXTRA_LIBS" >&5 +$as_echo "$PYTHON_EXTRA_LIBS" >&6; } + + + # + # linking flags needed when embedding + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking python extra linking flags" >&5 +$as_echo_n "checking python extra linking flags... " >&6; } + if test -z "$PYTHON_EXTRA_LDFLAGS"; then + PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print (conf('LINKFORSHARED'))"` + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_EXTRA_LDFLAGS" >&5 +$as_echo "$PYTHON_EXTRA_LDFLAGS" >&6; } + + + # + # final check to see if everything compiles alright + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking consistency of all components of python development environment" >&5 +$as_echo_n "checking consistency of all components of python development environment... " >&6; } + # save current global flags + ac_save_LIBS="$LIBS" + ac_save_CPPFLAGS="$CPPFLAGS" + LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS" + CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +Py_Initialize(); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + pythonexists=yes +else + pythonexists=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + # turn back to default flags + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pythonexists" >&5 +$as_echo "$pythonexists" >&6; } + + if test ! "x$pythonexists" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + Could not link test program to Python. Maybe the main Python library has been + installed in some non-standard library path. If so, pass it to configure, + via the LDFLAGS environment variable. + Example: ./configure LDFLAGS=\"-L/usr/non-standard-path/python/lib\" + ============================================================================ + You may have to install the development version of the Python package + for your distribution. The exact name of this package varies among them. + For example, the package may be called \"python2.6-dev\". For now, we are + skipping the build of the Python kvspool module + ============================================================================ + " >&5 +$as_echo "$as_me: WARNING: + Could not link test program to Python. Maybe the main Python library has been + installed in some non-standard library path. If so, pass it to configure, + via the LDFLAGS environment variable. + Example: ./configure LDFLAGS=\"-L/usr/non-standard-path/python/lib\" + ============================================================================ + You may have to install the development version of the Python package + for your distribution. The exact name of this package varies among them. + For example, the package may be called \"python2.6-dev\". For now, we are + skipping the build of the Python kvspool module + ============================================================================ + " >&2;} + PYTHON_VERSION="" + fi + + # + # all done! + # + + if test "x$pythonexists" = "xyes"; then + HAVE_PYTHON_TRUE= + HAVE_PYTHON_FALSE='#' +else + HAVE_PYTHON_TRUE='#' + HAVE_PYTHON_FALSE= +fi + + +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_PERL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PERL"; then + ac_cv_prog_PERL="$PERL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_PERL="perl" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PERL=$ac_cv_prog_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$PERL" != "x"; then + HAVE_PERL_TRUE= + HAVE_PERL_FALSE='#' +else + HAVE_PERL_TRUE='#' + HAVE_PERL_FALSE= +fi + + +ac_config_files="$ac_config_files Makefile utils/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_ZEROMQ_TRUE}" && test -z "${HAVE_ZEROMQ_FALSE}"; then + as_fn_error "conditional \"HAVE_ZEROMQ\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_ZEROMQ_TRUE}" && test -z "${HAVE_ZEROMQ_FALSE}"; then + as_fn_error "conditional \"HAVE_ZEROMQ\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then + as_fn_error "conditional \"HAVE_PYTHON\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PERL_TRUE}" && test -z "${HAVE_PERL_FALSE}"; then + as_fn_error "conditional \"HAVE_PERL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by kvspool $as_me 1.0, which was +generated by GNU Autoconf 2.65. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +kvspool config.status 1.0 +configured by $0, generated by GNU Autoconf 2.65, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config/config.h") CONFIG_HEADERS="$CONFIG_HEADERS config/config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "utils/Makefile") CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..07afff5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,24 @@ +AC_PREREQ(2.59) + +AC_INIT([kvspool], [1.0], [troy.hanson@jhuapl.edu]) +AC_CONFIG_SRCDIR(kvspool.c) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS(config/config.h) +AM_INIT_AUTOMAKE +AC_PROG_CC +AC_PROG_RANLIB + +# is zeromq (0MQ) installed +AC_CHECK_LIB(zmq,zmq_init, + AM_CONDITIONAL(HAVE_ZEROMQ,true), + AM_CONDITIONAL(HAVE_ZEROMQ,false)) + +AX_PYTHON_DEVEL(>= '2.4') +AM_CONDITIONAL(HAVE_PYTHON,test "x$pythonexists" = "xyes") + +AC_CHECK_PROG(PERL,perl,perl) +AM_CONDITIONAL(HAVE_PERL,test "x$PERL" != "x") + +AC_CONFIG_FILES(Makefile utils/Makefile) +AC_OUTPUT + diff --git a/kvperl/.gitignore b/kvperl/.gitignore new file mode 100644 index 0000000..24ab136 --- /dev/null +++ b/kvperl/.gitignore @@ -0,0 +1,5 @@ +KVSpool.bs +KVSpool.c +Makefile.gen +blib/ +pm_to_blib diff --git a/kvperl/Changes b/kvperl/Changes new file mode 100644 index 0000000..81f9a8a --- /dev/null +++ b/kvperl/Changes @@ -0,0 +1,6 @@ +Revision history for Perl extension KVSpool. + +0.01 Wed Jun 15 13:02:15 2011 + - original version; created by h2xs 1.23 with options + -n KVSpool kvspool.h + diff --git a/kvperl/KVSpool.xs b/kvperl/KVSpool.xs new file mode 100644 index 0000000..5623aad --- /dev/null +++ b/kvperl/KVSpool.xs @@ -0,0 +1,252 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include "ppport.h" + +#include + +#include "const-c.inc" + + +int hash_to_kvs(HV *hash, void *set) { + SV *pv; + int rc = -1; + char *k, *v; + int len = 0; + + while ((pv = hv_iternextsv(hash,&k,(I32*)&len))!= 0) { + STRLEN le; + v = SvPV(pv,le); + if (!k || !v) goto done; + kv_add(set, k,len, v,le); + } + rc = 0; + done: + return rc; +} + +SV** kvs_to_hash(HV **hash, void *set) { + SV *pv; //,*pk; + SV **rc = NULL; + + *hash = newHV(); + + kv_t *kv=NULL; + while ( (kv= kv_next(set,kv))) { + + pv = newSVpv(kv->val,kv->vlen); + rc = hv_store(*hash,kv->key,kv->klen,pv,0); + + if (rc == NULL) break; + } + + if (rc == NULL) { + hv_undef(*hash); + *hash = NULL; + } + return rc; +} +/* +*/ + + + +MODULE = KVSpool PACKAGE = KVSpool + +INCLUDE: const-xs.inc + + + +SV* +makersp(char * dir,char * base) +PREINIT: +void *sp; +CODE: + if (*base == '\0') base=NULL; + + if ( (sp = kv_spoolreader_new(dir,base)) == NULL) { + croak("cannot initialize spool reader"); + } + //IV pv = PTR2IV(sp); + SV* pv = newSViv(PTR2IV(sp)); +// printf("%i %i\n",SvUV(pv),sp); + //printf("IV is %"IVdf" %i\n", pv,sp); + + RETVAL = pv;//newRV(pv); +OUTPUT: + RETVAL + + + + +SV* +makewsp(char * dir,char * base) +PREINIT: +void *sp; +CODE: + if (*base == '\0') base=NULL; + + if ( (sp = kv_spoolwriter_new(dir,base)) == NULL) { + croak("cannot initialize spool reader"); + } + SV* pv = newSViv(PTR2IV(sp)); + + RETVAL = pv;//newRV(pv); +OUTPUT: + RETVAL + + +void +freersp(IV pos) +INIT: + void *sp; +CODE: + sp = INT2PTR(void*,pos); + kv_spoolreader_free(sp); + + +void +freewsp(IV pos) +INIT: + void *sp; +CODE: + sp = INT2PTR(void*,pos); + kv_spoolwriter_free(sp); + + + +HV* +kvread(IV pos,int block) +INIT: + void *set,*sp; + HV *hash = NULL; + int rc =0; + SV** val; +CODE: + sp = INT2PTR(void*,pos); + + set = kv_set_new(); + if ( (rc=kv_spool_read(sp,set,block)) > 0) { + kvs_to_hash(&hash, set); + kv_set_free(set); + RETVAL = hash; + } else if (rc == 0) { + kv_set_free(set); + RETVAL = newHV(); + //croak("no frames available"); + } else if (rc < 0) { + kv_set_free(set); + croak("internal error in spool reader"); + } +OUTPUT: + RETVAL + + +void +kvwrite(IV pos, HV* hash) +INIT: + void *sp, *set; +CODE: + sp = INT2PTR(void*,pos); + set = kv_set_new(); + if (hash_to_kvs(hash, set) == -1) { + kv_set_free(set); + croak("non-string key or value"); + } + kv_spool_write(sp,set); + kv_set_free(set); + +HV* +kv_read(char * dir,char * base, int block) +PREINIT: +void *sp,*set; +HV *hash = NULL; +int rc = 0; +CODE: + if (*base == '\0') base=NULL; + block = block ? 1 : 0; + + if ( (sp = kv_spoolreader_new(dir,base)) == NULL) { + croak("cannot initialize spool reader"); + RETVAL = NULL; + } + + set = kv_set_new(); + if ( (rc=kv_spool_read(sp,set,block)) > 0) { + kvs_to_hash(&hash, set); + RETVAL = hash; + } else if (rc == 0) { + kv_set_free(set); + kv_spoolreader_free(sp); + RETVAL = (HV*)sv_2mortal((SV*)newHV()); + croak("no frames available"); + } else if (rc < 0) { + kv_set_free(set); + kv_spoolreader_free(sp); + croak("internal error in spool reader"); + } + kv_set_free(set); + kv_spoolreader_free(sp); +OUTPUT: + RETVAL + +void +kv_write(char * dir,char * base, HV* hash) +INIT: + void *sp, *set; +CODE: + /* normalize inputs */ + if (*base == '\0') { + croak("base cannot be empty"); + } + + /* try to write a spool frame */ + if ( (sp = kv_spoolwriter_new(dir,base)) == NULL) { + croak("cannot initialize spool writer"); + } + + set = kv_set_new(); + if (hash_to_kvs(hash, set) == -1) { + croak("non-string key or value"); + } + kv_spool_write(sp,set); + kv_set_free(set); + kv_spoolwriter_free(sp); + + + +HV* +kv_stat(char * dir, char * base) +INIT: + int sc, i; + SV** rc = NULL; + kv_stat_t *stats; + HV *hash = NULL; + SV *pv; +CODE: + if (*base == '\0') base=NULL; + + sc = kv_stat(dir,base,&stats); + if (sc == -1) { + croak("kv_stat failed"); + } + + hash = newHV(); + for(i=0; i < sc; i++) { + pv = sv_2mortal(newSViv((long)(stats[i].pct_consumed))); + rc = hv_store(hash,stats[i].base,strlen(stats[i].base),pv,0); + if (rc == NULL) break; + } + if (stats) free(stats); + if (rc == NULL) { + sv_2mortal((SV*)hash); + hash = NULL; + } + + RETVAL = hash; +OUTPUT: + RETVAL + + + diff --git a/kvperl/MANIFEST b/kvperl/MANIFEST new file mode 100644 index 0000000..53873ff --- /dev/null +++ b/kvperl/MANIFEST @@ -0,0 +1,10 @@ +Changes +KVSpool.xs +Makefile.PL +MANIFEST +ppport.h +README +t/KVSpool.t +fallback/const-c.inc +fallback/const-xs.inc +lib/KVSpool.pm diff --git a/kvperl/Makefile b/kvperl/Makefile new file mode 100644 index 0000000..e382456 --- /dev/null +++ b/kvperl/Makefile @@ -0,0 +1,3 @@ +all distclean clean install: + perl -f Makefile.PL + make -f Makefile.gen $@ diff --git a/kvperl/Makefile.PL b/kvperl/Makefile.PL new file mode 100644 index 0000000..ff94491 --- /dev/null +++ b/kvperl/Makefile.PL @@ -0,0 +1,41 @@ +use 5.010001; +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + FIRST_MAKEFILE => 'Makefile.gen', + NAME => 'KVSpool', + VERSION_FROM => 'lib/KVSpool.pm', # finds $VERSION + PREREQ_PM => {}, # e.g., Module::Name => 1.1 + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'lib/KVSpool.pm', # retrieve abstract from module + AUTHOR => 'A. U. Thor ') : ()), + LIBS => ['-L.. -lkvspool'], # e.g., '-lm' + DEFINE => '', # e.g., '-DHAVE_SOMETHING' + INC => '-I. -I..', # e.g., '-I. -I/usr/include/other' + # Un-comment this if you add C files to link with later: + # OBJECT => '$(O_FILES)', # link all the C files too +); +if (eval {require ExtUtils::Constant; 1}) { + # If you edit these definitions to change the constants used by this module, + # you will need to use the generated const-c.inc and const-xs.inc + # files to replace their "fallback" counterparts before distributing your + # changes. + my @names = (qw(KV_BASE_MAX)); + ExtUtils::Constant::WriteConstants( + NAME => 'KVSpool', + NAMES => \@names, + DEFAULT_TYPE => 'IV', + C_FILE => 'const-c.inc', + XS_FILE => 'const-xs.inc', + ); + +} +else { + use File::Copy; + use File::Spec; + foreach my $file ('const-c.inc', 'const-xs.inc') { + my $fallback = File::Spec->catfile('fallback', $file); + copy ($fallback, $file) or die "Can't copy $fallback to $file: $!"; + } +} diff --git a/kvperl/Makefile.gen.old b/kvperl/Makefile.gen.old new file mode 100644 index 0000000..7b39277 --- /dev/null +++ b/kvperl/Makefile.gen.old @@ -0,0 +1,944 @@ +# This Makefile is for the KVSpool extension to perl. +# +# It was generated automatically by MakeMaker version +# 6.55_02 (Revision: 65502) from the contents of +# Makefile.PL. Don't edit this file, edit Makefile.PL instead. +# +# ANY CHANGES MADE HERE WILL BE LOST! +# +# MakeMaker ARGV: () +# + +# MakeMaker Parameters: + +# ABSTRACT_FROM => q[lib/KVSpool.pm] +# AUTHOR => q[A. U. Thor ] +# BUILD_REQUIRES => { } +# DEFINE => q[] +# FIRST_MAKEFILE => q[Makefile.gen] +# INC => q[-I. -I..] +# LIBS => [q[-L.. -lkvspool]] +# NAME => q[KVSpool] +# PREREQ_PM => { } +# VERSION_FROM => q[lib/KVSpool.pm] + +# --- MakeMaker post_initialize section: + + +# --- MakeMaker const_config section: + +# These definitions are from config.sh (via /usr/lib/perl/5.10/Config.pm). +# They may have been overridden via Makefile.PL or on the command line. +AR = ar +CC = cc +CCCDLFLAGS = -fPIC +CCDLFLAGS = -Wl,-E +DLEXT = so +DLSRC = dl_dlopen.xs +EXE_EXT = +FULL_AR = /usr/bin/ar +LD = cc +LDDLFLAGS = -shared -O2 -g -L/usr/local/lib -fstack-protector +LDFLAGS = -fstack-protector -L/usr/local/lib +LIBC = /lib/libc-2.11.1.so +LIB_EXT = .a +OBJ_EXT = .o +OSNAME = linux +OSVERS = 2.6.24-27-server +RANLIB = : +SITELIBEXP = /usr/local/share/perl/5.10.1 +SITEARCHEXP = /usr/local/lib/perl/5.10.1 +SO = so +VENDORARCHEXP = /usr/lib/perl5 +VENDORLIBEXP = /usr/share/perl5 + + +# --- MakeMaker constants section: +AR_STATIC_ARGS = cr +DIRFILESEP = / +DFSEP = $(DIRFILESEP) +NAME = KVSpool +NAME_SYM = KVSpool +VERSION = 0.01 +VERSION_MACRO = VERSION +VERSION_SYM = 0_01 +DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\" +XS_VERSION = 0.01 +XS_VERSION_MACRO = XS_VERSION +XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\" +INST_ARCHLIB = blib/arch +INST_SCRIPT = blib/script +INST_BIN = blib/bin +INST_LIB = blib/lib +INST_MAN1DIR = blib/man1 +INST_MAN3DIR = blib/man3 +MAN1EXT = 1p +MAN3EXT = 3pm +INSTALLDIRS = site +DESTDIR = +PREFIX = /usr +PERLPREFIX = $(PREFIX) +SITEPREFIX = $(PREFIX)/local +VENDORPREFIX = $(PREFIX) +INSTALLPRIVLIB = $(PERLPREFIX)/share/perl/5.10 +DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB) +INSTALLSITELIB = $(SITEPREFIX)/share/perl/5.10.1 +DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB) +INSTALLVENDORLIB = $(VENDORPREFIX)/share/perl5 +DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB) +INSTALLARCHLIB = $(PERLPREFIX)/lib/perl/5.10 +DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB) +INSTALLSITEARCH = $(SITEPREFIX)/lib/perl/5.10.1 +DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH) +INSTALLVENDORARCH = $(VENDORPREFIX)/lib/perl5 +DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH) +INSTALLBIN = $(PERLPREFIX)/bin +DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN) +INSTALLSITEBIN = $(SITEPREFIX)/bin +DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN) +INSTALLVENDORBIN = $(VENDORPREFIX)/bin +DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN) +INSTALLSCRIPT = $(PERLPREFIX)/bin +DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT) +INSTALLSITESCRIPT = $(SITEPREFIX)/bin +DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT) +INSTALLVENDORSCRIPT = $(VENDORPREFIX)/bin +DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT) +INSTALLMAN1DIR = $(PERLPREFIX)/share/man/man1 +DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR) +INSTALLSITEMAN1DIR = $(SITEPREFIX)/man/man1 +DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR) +INSTALLVENDORMAN1DIR = $(VENDORPREFIX)/share/man/man1 +DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR) +INSTALLMAN3DIR = $(PERLPREFIX)/share/man/man3 +DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR) +INSTALLSITEMAN3DIR = $(SITEPREFIX)/man/man3 +DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR) +INSTALLVENDORMAN3DIR = $(VENDORPREFIX)/share/man/man3 +DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR) +PERL_LIB = /usr/share/perl/5.10 +PERL_ARCHLIB = /usr/lib/perl/5.10 +LIBPERL_A = libperl.a +FIRST_MAKEFILE = Makefile.gen +MAKEFILE_OLD = Makefile.gen.old +MAKE_APERL_FILE = Makefile.gen.aperl +PERLMAINCC = $(CC) +PERL_INC = /usr/lib/perl/5.10/CORE +PERL = /usr/bin/perl +FULLPERL = /usr/bin/perl +ABSPERL = $(PERL) +PERLRUN = $(PERL) +FULLPERLRUN = $(FULLPERL) +ABSPERLRUN = $(ABSPERL) +PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +PERL_CORE = 0 +PERM_DIR = 755 +PERM_RW = 644 +PERM_RWX = 755 + +MAKEMAKER = /usr/share/perl/5.10/ExtUtils/MakeMaker.pm +MM_VERSION = 6.55_02 +MM_REVISION = 65502 + +# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). +# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) +# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) +# DLBASE = Basename part of dynamic library. May be just equal BASEEXT. +MAKE = make +FULLEXT = KVSpool +BASEEXT = KVSpool +PARENT_NAME = +DLBASE = $(BASEEXT) +VERSION_FROM = lib/KVSpool.pm +INC = -I. -I.. +DEFINE = +OBJECT = $(BASEEXT)$(OBJ_EXT) +LDFROM = $(OBJECT) +LINKTYPE = dynamic +BOOTDEP = + +# Handy lists of source code files: +XS_FILES = KVSpool.xs +C_FILES = KVSpool.c +O_FILES = KVSpool.o +H_FILES = ppport.h +MAN1PODS = +MAN3PODS = lib/KVSpool.pm + +# Where is the Config information that we are using/depend on +CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h + +# Where to build things +INST_LIBDIR = $(INST_LIB) +INST_ARCHLIBDIR = $(INST_ARCHLIB) + +INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT) +INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT) + +INST_STATIC = $(INST_ARCHAUTODIR)/$(BASEEXT)$(LIB_EXT) +INST_DYNAMIC = $(INST_ARCHAUTODIR)/$(DLBASE).$(DLEXT) +INST_BOOT = $(INST_ARCHAUTODIR)/$(BASEEXT).bs + +# Extra linker info +EXPORT_LIST = +PERL_ARCHIVE = +PERL_ARCHIVE_AFTER = + + +TO_INST_PM = lib/KVSpool.pm + +PM_TO_BLIB = lib/KVSpool.pm \ + blib/lib/KVSpool.pm + + +# --- MakeMaker platform_constants section: +MM_Unix_VERSION = 6.55_02 +PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc + + +# --- MakeMaker tool_autosplit section: +# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto +AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)' -- + + + +# --- MakeMaker tool_xsubpp section: + +XSUBPPDIR = /usr/share/perl/5.10/ExtUtils +XSUBPP = $(XSUBPPDIR)$(DFSEP)xsubpp +XSUBPPRUN = $(PERLRUN) $(XSUBPP) +XSPROTOARG = +XSUBPPDEPS = /usr/share/perl/5.10/ExtUtils/typemap $(XSUBPP) +XSUBPPARGS = -typemap /usr/share/perl/5.10/ExtUtils/typemap +XSUBPP_EXTRA_ARGS = + + +# --- MakeMaker tools_other section: +SHELL = /bin/sh +CHMOD = chmod +CP = cp +MV = mv +NOOP = $(TRUE) +NOECHO = @ +RM_F = rm -f +RM_RF = rm -rf +TEST_F = test -f +TOUCH = touch +UMASK_NULL = umask 0 +DEV_NULL = > /dev/null 2>&1 +MKPATH = $(ABSPERLRUN) -MExtUtils::Command -e 'mkpath' -- +EQUALIZE_TIMESTAMP = $(ABSPERLRUN) -MExtUtils::Command -e 'eqtime' -- +FALSE = false +TRUE = true +ECHO = echo +ECHO_N = echo -n +UNINST = 0 +VERBINST = 0 +MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install([ from_to => {@ARGV}, verbose => '\''$(VERBINST)'\'', uninstall_shadows => '\''$(UNINST)'\'', dir_mode => '\''$(PERM_DIR)'\'' ]);' -- +DOC_INSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'perllocal_install' -- +UNINSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'uninstall' -- +WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'warn_if_old_packlist' -- +MACROSTART = +MACROEND = +USEMAKEFILE = -f +FIXIN = $(ABSPERLRUN) -MExtUtils::MY -e 'MY->fixin(shift)' -- + + +# --- MakeMaker makemakerdflt section: +makemakerdflt : all + $(NOECHO) $(NOOP) + + +# --- MakeMaker dist section: +TAR = tar +TARFLAGS = cvf +ZIP = zip +ZIPFLAGS = -r +COMPRESS = gzip --best +SUFFIX = .gz +SHAR = shar +PREOP = $(NOECHO) $(NOOP) +POSTOP = $(NOECHO) $(NOOP) +TO_UNIX = $(NOECHO) $(NOOP) +CI = ci -u +RCS_LABEL = rcs -Nv$(VERSION_SYM): -q +DIST_CP = best +DIST_DEFAULT = tardist +DISTNAME = KVSpool +DISTVNAME = KVSpool-0.01 + + +# --- MakeMaker macro section: + + +# --- MakeMaker depend section: + + +# --- MakeMaker cflags section: + +CCFLAGS = -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 +OPTIMIZE = -O2 -g +PERLTYPE = +MPOLLUTE = + + +# --- MakeMaker const_loadlibs section: + +# KVSpool might depend on some other libraries: +# See ExtUtils::Liblist for details +# +EXTRALIBS = -L/home/thanson/checkouts/cic/linux/kvspool/kvperl/.. -lkvspool +LDLOADLIBS = -L/home/thanson/checkouts/cic/linux/kvspool/kvperl/.. -lkvspool +BSLOADLIBS = + + +# --- MakeMaker const_cccmd section: +CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \ + $(CCFLAGS) $(OPTIMIZE) \ + $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \ + $(XS_DEFINE_VERSION) + +# --- MakeMaker post_constants section: + + +# --- MakeMaker pasthru section: + +PASTHRU = LIBPERL_A="$(LIBPERL_A)"\ + LINKTYPE="$(LINKTYPE)"\ + OPTIMIZE="$(OPTIMIZE)"\ + PREFIX="$(PREFIX)"\ + PASTHRU_DEFINE="$(PASTHRU_DEFINE)"\ + PASTHRU_INC="$(PASTHRU_INC)" + + +# --- MakeMaker special_targets section: +.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT) + +.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir + + + +# --- MakeMaker c_o section: + +.c.i: + cc -E -c $(PASTHRU_INC) $(INC) \ + $(CCFLAGS) $(OPTIMIZE) \ + $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \ + $(XS_DEFINE_VERSION) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c > $*.i + +.c.s: + $(CCCMD) -S $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + +.c$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + +.cpp$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cpp + +.cxx$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cxx + +.cc$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cc + +.C$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.C + + +# --- MakeMaker xs_c section: + +.xs.c: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c + + +# --- MakeMaker xs_o section: + +.xs$(OBJ_EXT): + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + + +# --- MakeMaker top_targets section: +all :: pure_all manifypods + $(NOECHO) $(NOOP) + + +pure_all :: config pm_to_blib subdirs linkext + $(NOECHO) $(NOOP) + +subdirs :: $(MYEXTLIB) + $(NOECHO) $(NOOP) + +config :: $(FIRST_MAKEFILE) blibdirs + $(NOECHO) $(NOOP) + +$(O_FILES): $(H_FILES) + +help : + perldoc ExtUtils::MakeMaker + + +# --- MakeMaker blibdirs section: +blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists + $(NOECHO) $(NOOP) + +# Backwards compat with 6.18 through 6.25 +blibdirs.ts : blibdirs + $(NOECHO) $(NOOP) + +$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_LIBDIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_LIBDIR) + $(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists + +$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHLIB) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHLIB) + $(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists + +$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_AUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_AUTODIR) + $(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists + +$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHAUTODIR) + $(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists + +$(INST_BIN)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_BIN) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_BIN) + $(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists + +$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_SCRIPT) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_SCRIPT) + $(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists + +$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN1DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN1DIR) + $(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists + +$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN3DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN3DIR) + $(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists + + + +# --- MakeMaker linkext section: + +linkext :: $(LINKTYPE) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dlsyms section: + + +# --- MakeMaker dynamic section: + +dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dynamic_bs section: +BOOTSTRAP = $(BASEEXT).bs + +# As Mkbootstrap might not write a file (if none is required) +# we use touch to prevent make continually trying to remake it. +# The DynaLoader only reads a non-empty file. +$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))" + $(NOECHO) $(PERLRUN) \ + "-MExtUtils::Mkbootstrap" \ + -e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');" + $(NOECHO) $(TOUCH) $@ + $(CHMOD) $(PERM_RW) $@ + +$(INST_BOOT) : $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(RM_RF) $@ + - $(CP) $(BOOTSTRAP) $@ + $(CHMOD) $(PERM_RW) $@ + + +# --- MakeMaker dynamic_lib section: + +# This section creates the dynamically loadable $(INST_DYNAMIC) +# from $(OBJECT) and possibly $(MYEXTLIB). +ARMAYBE = : +OTHERLDFLAGS = +INST_DYNAMIC_DEP = +INST_DYNAMIC_FIX = + +$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP) + $(RM_F) $@ + $(LD) $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) \ + $(PERL_ARCHIVE) $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) \ + $(INST_DYNAMIC_FIX) + $(CHMOD) $(PERM_RWX) $@ + + +# --- MakeMaker static section: + +## $(INST_PM) has been moved to the all: target. +## It remains here for awhile to allow for old usage: "make static" +static :: $(FIRST_MAKEFILE) $(INST_STATIC) + $(NOECHO) $(NOOP) + + +# --- MakeMaker static_lib section: + +$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(RM_RF) $@ + $(FULL_AR) $(AR_STATIC_ARGS) $@ $(OBJECT) && $(RANLIB) $@ + $(CHMOD) $(PERM_RWX) $@ + $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)/extralibs.ld + + +# --- MakeMaker manifypods section: + +POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--" +POD2MAN = $(POD2MAN_EXE) + + +manifypods : pure_all \ + lib/KVSpool.pm + $(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) \ + lib/KVSpool.pm $(INST_MAN3DIR)/KVSpool.$(MAN3EXT) + + + + +# --- MakeMaker processPL section: + + +# --- MakeMaker installbin section: + + +# --- MakeMaker subdirs section: + +# none + +# --- MakeMaker clean_subdirs section: +clean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker clean section: + +# Delete temporary files but do not touch installed files. We don't delete +# the Makefile here so a later make realclean still has a makefile to use. + +clean :: clean_subdirs + - $(RM_F) \ + *$(LIB_EXT) core \ + core.[0-9] $(INST_ARCHAUTODIR)/extralibs.all \ + KVSpool.c core.[0-9][0-9] \ + $(BASEEXT).bso pm_to_blib.ts \ + core.[0-9][0-9][0-9][0-9] $(BASEEXT).x \ + $(BOOTSTRAP) perl$(EXE_EXT) \ + tmon.out *$(OBJ_EXT) \ + pm_to_blib $(INST_ARCHAUTODIR)/extralibs.ld \ + blibdirs.ts core.[0-9][0-9][0-9][0-9][0-9] \ + *perl.core core.*perl.*.? \ + $(MAKE_APERL_FILE) perl \ + $(BASEEXT).def core.[0-9][0-9][0-9] \ + mon.out lib$(BASEEXT).def \ + perlmain.c perl.exe \ + so_locations $(BASEEXT).exp + - $(RM_RF) \ + blib + - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL) + + +# --- MakeMaker realclean_subdirs section: +realclean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker realclean section: +# Delete temporary files (via clean) and also delete dist files +realclean purge :: clean realclean_subdirs + - $(RM_F) \ + $(OBJECT) $(MAKEFILE_OLD) \ + $(FIRST_MAKEFILE) + - $(RM_RF) \ + $(DISTVNAME) + + +# --- MakeMaker metafile section: +metafile : create_distdir + $(NOECHO) $(ECHO) Generating META.yml + $(NOECHO) $(ECHO) '--- #YAML:1.0' > META_new.yml + $(NOECHO) $(ECHO) 'name: KVSpool' >> META_new.yml + $(NOECHO) $(ECHO) 'version: 0.01' >> META_new.yml + $(NOECHO) $(ECHO) 'abstract: Perl extension for blah blah blah' >> META_new.yml + $(NOECHO) $(ECHO) 'author:' >> META_new.yml + $(NOECHO) $(ECHO) ' - A. U. Thor ' >> META_new.yml + $(NOECHO) $(ECHO) 'license: unknown' >> META_new.yml + $(NOECHO) $(ECHO) 'distribution_type: module' >> META_new.yml + $(NOECHO) $(ECHO) 'configure_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: 0' >> META_new.yml + $(NOECHO) $(ECHO) 'build_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: 0' >> META_new.yml + $(NOECHO) $(ECHO) 'requires: {}' >> META_new.yml + $(NOECHO) $(ECHO) 'no_index:' >> META_new.yml + $(NOECHO) $(ECHO) ' directory:' >> META_new.yml + $(NOECHO) $(ECHO) ' - t' >> META_new.yml + $(NOECHO) $(ECHO) ' - inc' >> META_new.yml + $(NOECHO) $(ECHO) 'generated_by: ExtUtils::MakeMaker version 6.55_02' >> META_new.yml + $(NOECHO) $(ECHO) 'meta-spec:' >> META_new.yml + $(NOECHO) $(ECHO) ' url: http://module-build.sourceforge.net/META-spec-v1.4.html' >> META_new.yml + $(NOECHO) $(ECHO) ' version: 1.4' >> META_new.yml + -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml + + +# --- MakeMaker signature section: +signature : + cpansign -s + + +# --- MakeMaker dist_basics section: +distclean :: realclean distcheck + $(NOECHO) $(NOOP) + +distcheck : + $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck + +skipcheck : + $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck + +manifest : + $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest + +veryclean : realclean + $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old + + + +# --- MakeMaker dist_core section: + +dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE) + $(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \ + -e ' if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\'' < -M '\''$(FIRST_MAKEFILE)'\'';' -- + +tardist : $(DISTVNAME).tar$(SUFFIX) + $(NOECHO) $(NOOP) + +uutardist : $(DISTVNAME).tar$(SUFFIX) + uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu + +$(DISTVNAME).tar$(SUFFIX) : distdir + $(PREOP) + $(TO_UNIX) + $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(COMPRESS) $(DISTVNAME).tar + $(POSTOP) + +zipdist : $(DISTVNAME).zip + $(NOECHO) $(NOOP) + +$(DISTVNAME).zip : distdir + $(PREOP) + $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(POSTOP) + +shdist : distdir + $(PREOP) + $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar + $(RM_RF) $(DISTVNAME) + $(POSTOP) + + +# --- MakeMaker distdir section: +create_distdir : + $(RM_RF) $(DISTVNAME) + $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \ + -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');" + +distdir : create_distdir distmeta + $(NOECHO) $(NOOP) + + + +# --- MakeMaker dist_test section: +disttest : distdir + cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL + cd $(DISTVNAME) && $(MAKE) $(PASTHRU) + cd $(DISTVNAME) && $(MAKE) test $(PASTHRU) + + + +# --- MakeMaker dist_ci section: + +ci : + $(PERLRUN) "-MExtUtils::Manifest=maniread" \ + -e "@all = keys %{ maniread() };" \ + -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \ + -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});" + + +# --- MakeMaker distmeta section: +distmeta : create_distdir metafile + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{META.yml} => q{Module meta-data (added by MakeMaker)}}) } ' \ + -e ' or print "Could not add META.yml to MANIFEST: $${'\''@'\''}\n"' -- + + + +# --- MakeMaker distsignature section: +distsignature : create_distdir + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } ' \ + -e ' or print "Could not add SIGNATURE to MANIFEST: $${'\''@'\''}\n"' -- + $(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE + cd $(DISTVNAME) && cpansign -s + + + +# --- MakeMaker install section: + +install :: pure_install doc_install + $(NOECHO) $(NOOP) + +install_perl :: pure_perl_install doc_perl_install + $(NOECHO) $(NOOP) + +install_site :: pure_site_install doc_site_install + $(NOECHO) $(NOOP) + +install_vendor :: pure_vendor_install doc_vendor_install + $(NOECHO) $(NOOP) + +pure_install :: pure_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +doc_install :: doc_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +pure__install : pure_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +doc__install : doc_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +pure_perl_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + $(INST_LIB) $(DESTINSTALLPRIVLIB) \ + $(INST_ARCHLIB) $(DESTINSTALLARCHLIB) \ + $(INST_BIN) $(DESTINSTALLBIN) \ + $(INST_SCRIPT) $(DESTINSTALLSCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLMAN3DIR) + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + $(SITEARCHEXP)/auto/$(FULLEXT) + + +pure_site_install :: all + $(NOECHO) umask 02; $(MOD_INSTALL) \ + read $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist \ + write $(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist \ + $(INST_LIB) $(DESTINSTALLSITELIB) \ + $(INST_ARCHLIB) $(DESTINSTALLSITEARCH) \ + $(INST_BIN) $(DESTINSTALLSITEBIN) \ + $(INST_SCRIPT) $(DESTINSTALLSITESCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR) + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + $(PERL_ARCHLIB)/auto/$(FULLEXT) + +pure_vendor_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + $(INST_LIB) $(DESTINSTALLVENDORLIB) \ + $(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) \ + $(INST_BIN) $(DESTINSTALLVENDORBIN) \ + $(INST_SCRIPT) $(DESTINSTALLVENDORSCRIPT) \ + $(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) \ + $(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR) + +doc_perl_install :: all + +doc_site_install :: all + $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLSITEARCH)/perllocal.pod + -$(NOECHO) umask 02; $(MKPATH) $(DESTINSTALLSITEARCH) + -$(NOECHO) umask 02; $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" "$(INSTALLSITELIB)" \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> $(DESTINSTALLSITEARCH)/perllocal.pod + +doc_vendor_install :: all + + +uninstall :: uninstall_from_$(INSTALLDIRS)dirs + $(NOECHO) $(NOOP) + +uninstall_from_perldirs :: + +uninstall_from_sitedirs :: + $(NOECHO) $(UNINSTALL) $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist + +uninstall_from_vendordirs :: + + + +# --- MakeMaker force section: +# Phony target to force checking subdirectories. +FORCE : + $(NOECHO) $(NOOP) + + +# --- MakeMaker perldepend section: + +PERL_HDRS = \ + $(PERL_INC)/EXTERN.h \ + $(PERL_INC)/INTERN.h \ + $(PERL_INC)/XSUB.h \ + $(PERL_INC)/av.h \ + $(PERL_INC)/cc_runtime.h \ + $(PERL_INC)/config.h \ + $(PERL_INC)/cop.h \ + $(PERL_INC)/cv.h \ + $(PERL_INC)/dosish.h \ + $(PERL_INC)/embed.h \ + $(PERL_INC)/embedvar.h \ + $(PERL_INC)/fakethr.h \ + $(PERL_INC)/form.h \ + $(PERL_INC)/gv.h \ + $(PERL_INC)/handy.h \ + $(PERL_INC)/hv.h \ + $(PERL_INC)/intrpvar.h \ + $(PERL_INC)/iperlsys.h \ + $(PERL_INC)/keywords.h \ + $(PERL_INC)/mg.h \ + $(PERL_INC)/nostdio.h \ + $(PERL_INC)/op.h \ + $(PERL_INC)/opcode.h \ + $(PERL_INC)/patchlevel.h \ + $(PERL_INC)/perl.h \ + $(PERL_INC)/perlio.h \ + $(PERL_INC)/perlsdio.h \ + $(PERL_INC)/perlsfio.h \ + $(PERL_INC)/perlvars.h \ + $(PERL_INC)/perly.h \ + $(PERL_INC)/pp.h \ + $(PERL_INC)/pp_proto.h \ + $(PERL_INC)/proto.h \ + $(PERL_INC)/regcomp.h \ + $(PERL_INC)/regexp.h \ + $(PERL_INC)/regnodes.h \ + $(PERL_INC)/scope.h \ + $(PERL_INC)/sv.h \ + $(PERL_INC)/thread.h \ + $(PERL_INC)/unixish.h \ + $(PERL_INC)/util.h + +$(OBJECT) : $(PERL_HDRS) + +KVSpool.c : $(XSUBPPDEPS) + + +# --- MakeMaker makefile section: + +$(OBJECT) : $(FIRST_MAKEFILE) + +# We take a very conservative approach here, but it's worth it. +# We move Makefile to Makefile.old here to avoid gnu make looping. +$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP) + $(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?" + $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..." + -$(NOECHO) $(RM_F) $(MAKEFILE_OLD) + -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) + - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL) + $(PERLRUN) Makefile.PL + $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <==" + $(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command. <==" + $(FALSE) + + + +# --- MakeMaker staticmake section: + +# --- MakeMaker makeaperl section --- +MAP_TARGET = perl +FULLPERL = /usr/bin/perl + +$(MAP_TARGET) :: static $(MAKE_APERL_FILE) + $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@ + +$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib + $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET) + $(NOECHO) $(PERLRUNINST) \ + Makefile.PL DIR= \ + MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ + MAKEAPERL=1 NORECURS=1 CCCDLFLAGS= + + +# --- MakeMaker test section: + +TEST_VERBOSE=0 +TEST_TYPE=test_$(LINKTYPE) +TEST_FILE = test.pl +TEST_FILES = t/*.t +TESTDB_SW = -d + +testdb :: testdb_$(LINKTYPE) + +test :: $(TEST_TYPE) subdirs-test + +subdirs-test :: + $(NOECHO) $(NOOP) + + +test_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES) + PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +testdb_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +test_ : test_dynamic + +test_static :: pure_all $(MAP_TARGET) + PERL_DL_NONLAZY=1 ./$(MAP_TARGET) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES) + PERL_DL_NONLAZY=1 ./$(MAP_TARGET) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +testdb_static :: pure_all $(MAP_TARGET) + PERL_DL_NONLAZY=1 ./$(MAP_TARGET) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + + + +# --- MakeMaker ppd section: +# Creates a PPD (Perl Package Description) for a binary distribution. +ppd : + $(NOECHO) $(ECHO) '' > $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' Perl extension for blah blah blah' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' A. U. Thor <adamstr1@>' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) '' >> $(DISTNAME).ppd + + +# --- MakeMaker pm_to_blib section: + +pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM) + $(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', q[$(PM_FILTER)], '\''$(PERM_DIR)'\'')' -- \ + lib/KVSpool.pm blib/lib/KVSpool.pm + $(NOECHO) $(TOUCH) pm_to_blib + + +# --- MakeMaker selfdocument section: + + +# --- MakeMaker postamble section: + + +# End. diff --git a/kvperl/README b/kvperl/README new file mode 100644 index 0000000..04238bd --- /dev/null +++ b/kvperl/README @@ -0,0 +1,40 @@ +KVSpool version 0.01 +==================== + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the +README file from a module distribution so that people browsing the +archive can use it get an idea of the modules uses. It is usually a +good idea to provide version information here so that people can +decide whether fixes for the module are worth downloading. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + + blah blah blah + +COPYRIGHT AND LICENCE + +Put the correct copyright and licence information here. + +Copyright (C) 2011 by A. U. Thor + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.10.1 or, +at your option, any later version of Perl 5 you may have available. + + diff --git a/kvperl/const-c.inc b/kvperl/const-c.inc new file mode 100644 index 0000000..1001c38 --- /dev/null +++ b/kvperl/const-c.inc @@ -0,0 +1,65 @@ +#define PERL_constant_NOTFOUND 1 +#define PERL_constant_NOTDEF 2 +#define PERL_constant_ISIV 3 +#define PERL_constant_ISNO 4 +#define PERL_constant_ISNV 5 +#define PERL_constant_ISPV 6 +#define PERL_constant_ISPVN 7 +#define PERL_constant_ISSV 8 +#define PERL_constant_ISUNDEF 9 +#define PERL_constant_ISUV 10 +#define PERL_constant_ISYES 11 + +#ifndef NVTYPE +typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */ +#endif +#ifndef aTHX_ +#define aTHX_ /* 5.6 or later define this for threading support. */ +#endif +#ifndef pTHX_ +#define pTHX_ /* 5.6 or later define this for threading support. */ +#endif + +static int +constant (pTHX_ const char *name, STRLEN len, IV *iv_return) { + /* Initially switch on the length of the name. */ + /* When generated this function returned values for the list of names given + in this section of perl code. Rather than manually editing these functions + to add or remove constants, which would result in this comment and section + of code becoming inaccurate, we recommend that you edit this section of + code, and use it to regenerate a new set of constant functions which you + then use to replace the originals. + + Regenerate these constant functions by feeding this entire source file to + perl -x + +#!/usr/bin/perl -w +use ExtUtils::Constant qw (constant_types C_constant XS_constant); + +my $types = {map {($_, 1)} qw(IV)}; +my @names = (qw(KV_BASE_MAX)); + +print constant_types(), "\n"; # macro defs +foreach (C_constant ("KVSpool", 'constant', 'IV', $types, undef, 3, @names) ) { + print $_, "\n"; # C constant subs +} +print "\n#### XS Section:\n"; +print XS_constant ("KVSpool", $types); +__END__ + */ + + switch (len) { + case 11: + if (memEQ(name, "KV_BASE_MAX", 11)) { +#ifdef KV_BASE_MAX + *iv_return = KV_BASE_MAX; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + diff --git a/kvperl/const-xs.inc b/kvperl/const-xs.inc new file mode 100644 index 0000000..f5db725 --- /dev/null +++ b/kvperl/const-xs.inc @@ -0,0 +1,90 @@ +void +constant(sv) + PREINIT: +#ifdef dXSTARG + dXSTARG; /* Faster if we have it. */ +#else + dTARGET; +#endif + STRLEN len; + int type; + IV iv; + /* NV nv; Uncomment this if you need to return NVs */ + /* const char *pv; Uncomment this if you need to return PVs */ + INPUT: + SV * sv; + const char * s = SvPV(sv, len); + PPCODE: + /* Change this to constant(aTHX_ s, len, &iv, &nv); + if you need to return both NVs and IVs */ + type = constant(aTHX_ s, len, &iv); + /* Return 1 or 2 items. First is error message, or undef if no error. + Second, if present, is found value */ + switch (type) { + case PERL_constant_NOTFOUND: + sv = + sv_2mortal(newSVpvf("%s is not a valid KVSpool macro", s)); + PUSHs(sv); + break; + case PERL_constant_NOTDEF: + sv = sv_2mortal(newSVpvf( + "Your vendor has not defined KVSpool macro %s, used", + s)); + PUSHs(sv); + break; + case PERL_constant_ISIV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHi(iv); + break; + /* Uncomment this if you need to return NOs + case PERL_constant_ISNO: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_no); + break; */ + /* Uncomment this if you need to return NVs + case PERL_constant_ISNV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHn(nv); + break; */ + /* Uncomment this if you need to return PVs + case PERL_constant_ISPV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, strlen(pv)); + break; */ + /* Uncomment this if you need to return PVNs + case PERL_constant_ISPVN: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, iv); + break; */ + /* Uncomment this if you need to return SVs + case PERL_constant_ISSV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(sv); + break; */ + /* Uncomment this if you need to return UNDEFs + case PERL_constant_ISUNDEF: + break; */ + /* Uncomment this if you need to return UVs + case PERL_constant_ISUV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHu((UV)iv); + break; */ + /* Uncomment this if you need to return YESs + case PERL_constant_ISYES: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_yes); + break; */ + default: + sv = sv_2mortal(newSVpvf( + "Unexpected return type %d while processing KVSpool macro %s, used", + type, s)); + PUSHs(sv); + } diff --git a/kvperl/fallback/const-c.inc b/kvperl/fallback/const-c.inc new file mode 100644 index 0000000..1001c38 --- /dev/null +++ b/kvperl/fallback/const-c.inc @@ -0,0 +1,65 @@ +#define PERL_constant_NOTFOUND 1 +#define PERL_constant_NOTDEF 2 +#define PERL_constant_ISIV 3 +#define PERL_constant_ISNO 4 +#define PERL_constant_ISNV 5 +#define PERL_constant_ISPV 6 +#define PERL_constant_ISPVN 7 +#define PERL_constant_ISSV 8 +#define PERL_constant_ISUNDEF 9 +#define PERL_constant_ISUV 10 +#define PERL_constant_ISYES 11 + +#ifndef NVTYPE +typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */ +#endif +#ifndef aTHX_ +#define aTHX_ /* 5.6 or later define this for threading support. */ +#endif +#ifndef pTHX_ +#define pTHX_ /* 5.6 or later define this for threading support. */ +#endif + +static int +constant (pTHX_ const char *name, STRLEN len, IV *iv_return) { + /* Initially switch on the length of the name. */ + /* When generated this function returned values for the list of names given + in this section of perl code. Rather than manually editing these functions + to add or remove constants, which would result in this comment and section + of code becoming inaccurate, we recommend that you edit this section of + code, and use it to regenerate a new set of constant functions which you + then use to replace the originals. + + Regenerate these constant functions by feeding this entire source file to + perl -x + +#!/usr/bin/perl -w +use ExtUtils::Constant qw (constant_types C_constant XS_constant); + +my $types = {map {($_, 1)} qw(IV)}; +my @names = (qw(KV_BASE_MAX)); + +print constant_types(), "\n"; # macro defs +foreach (C_constant ("KVSpool", 'constant', 'IV', $types, undef, 3, @names) ) { + print $_, "\n"; # C constant subs +} +print "\n#### XS Section:\n"; +print XS_constant ("KVSpool", $types); +__END__ + */ + + switch (len) { + case 11: + if (memEQ(name, "KV_BASE_MAX", 11)) { +#ifdef KV_BASE_MAX + *iv_return = KV_BASE_MAX; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + diff --git a/kvperl/fallback/const-xs.inc b/kvperl/fallback/const-xs.inc new file mode 100644 index 0000000..f5db725 --- /dev/null +++ b/kvperl/fallback/const-xs.inc @@ -0,0 +1,90 @@ +void +constant(sv) + PREINIT: +#ifdef dXSTARG + dXSTARG; /* Faster if we have it. */ +#else + dTARGET; +#endif + STRLEN len; + int type; + IV iv; + /* NV nv; Uncomment this if you need to return NVs */ + /* const char *pv; Uncomment this if you need to return PVs */ + INPUT: + SV * sv; + const char * s = SvPV(sv, len); + PPCODE: + /* Change this to constant(aTHX_ s, len, &iv, &nv); + if you need to return both NVs and IVs */ + type = constant(aTHX_ s, len, &iv); + /* Return 1 or 2 items. First is error message, or undef if no error. + Second, if present, is found value */ + switch (type) { + case PERL_constant_NOTFOUND: + sv = + sv_2mortal(newSVpvf("%s is not a valid KVSpool macro", s)); + PUSHs(sv); + break; + case PERL_constant_NOTDEF: + sv = sv_2mortal(newSVpvf( + "Your vendor has not defined KVSpool macro %s, used", + s)); + PUSHs(sv); + break; + case PERL_constant_ISIV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHi(iv); + break; + /* Uncomment this if you need to return NOs + case PERL_constant_ISNO: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_no); + break; */ + /* Uncomment this if you need to return NVs + case PERL_constant_ISNV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHn(nv); + break; */ + /* Uncomment this if you need to return PVs + case PERL_constant_ISPV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, strlen(pv)); + break; */ + /* Uncomment this if you need to return PVNs + case PERL_constant_ISPVN: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, iv); + break; */ + /* Uncomment this if you need to return SVs + case PERL_constant_ISSV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(sv); + break; */ + /* Uncomment this if you need to return UNDEFs + case PERL_constant_ISUNDEF: + break; */ + /* Uncomment this if you need to return UVs + case PERL_constant_ISUV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHu((UV)iv); + break; */ + /* Uncomment this if you need to return YESs + case PERL_constant_ISYES: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_yes); + break; */ + default: + sv = sv_2mortal(newSVpvf( + "Unexpected return type %d while processing KVSpool macro %s, used", + type, s)); + PUSHs(sv); + } diff --git a/kvperl/lib/KVSpool.pm b/kvperl/lib/KVSpool.pm new file mode 100644 index 0000000..55f63e4 --- /dev/null +++ b/kvperl/lib/KVSpool.pm @@ -0,0 +1,159 @@ +package KVSpool; + +use 5.010001; +use strict; +use warnings; +use Carp; +use Data::Dumper; + +require Exporter; + +our @ISA = qw(Exporter); + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# This allows declaration use KVSpool ':all'; +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK +# will save memory. +our %EXPORT_TAGS = ( 'all' => [ qw( + KV_BASE_MAX +) ] ); + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw( + KV_BASE_MAX +); + +our $VERSION = '0.01'; + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. + + my $constname; + our $AUTOLOAD; + ($constname = $AUTOLOAD) =~ s/.*:://; + croak "&KVSpool::constant not defined" if $constname eq 'constant'; + my ($error, $val) = constant($constname); + if ($error) { croak $error; } + { + no strict 'refs'; + # Fixed between 5.005_53 and 5.005_61 +#XXX if ($] >= 5.00561) { +#XXX *$AUTOLOAD = sub () { $val }; +#XXX } +#XXX else { + *$AUTOLOAD = sub { $val }; +#XXX } + } + goto &$AUTOLOAD; +} + +require XSLoader; +XSLoader::load('KVSpool', $VERSION); + +# Preloaded methods go here. + +sub new { + my $class = shift; + my $dir = shift; + my $base = shift; + my $self = { + 'rsp' => 0, + 'wsp' => 0, + 'dir' => $dir, + 'base' => $base + }; + bless $self,$class; + return $self; +} +sub read { + my $self = shift; + my $block = shift; + if($self->{'rsp'} == 0){ + $self->{'rsp'} = makersp($self->{'dir'},$self->{'base'}); + } + return kvread($self->{'rsp'},$block); +} +sub write { + my $self = shift; + my $hash = shift; + if($self->{'wsp'} == 0){ + $self->{'wsp'} = makewsp($self->{'dir'},$self->{'base'}); + } + return kvwrite($self->{'wsp'},$hash); +} +sub stat { + my $self = shift; + return kv_stat($self->{'dir'},$self->{'base'}); +} + + +sub DESTROY { + my $self = shift; + freersp($self->{'rsp'}) if($self->{'rsp'} != 0); + freewsp($self->{'wsp'}) if($self->{'wsp'} != 0); + #$self->{'rsp'} = 0; + #$self->{'wsp'} = 0; +} +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is stub documentation for your module. You'd better edit it! + +=head1 NAME + +KVSpool - Perl extension for blah blah blah + +=head1 SYNOPSIS + + use KVSpool; + blah blah blah + +=head1 DESCRIPTION + +Stub documentation for KVSpool, created by h2xs. It looks like the +author of the extension was negligent enough to leave the stub +unedited. + +Blah blah blah. + +=head2 EXPORT + +None by default. + +=head2 Exportable constants + + KV_BASE_MAX + + + +=head1 SEE ALSO + +Mention other useful documentation such as the documentation of +related modules or operating system documentation (such as man pages +in UNIX), or any relevant external documentation such as RFCs or +standards. + +If you have a mailing list set up for your module, mention it here. + +If you have a web site set up for your module, mention it here. + +=head1 AUTHOR + +A. U. Thor, Eadamstr1@E + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2011 by A. U. Thor + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.10.1 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/kvperl/ppport.h b/kvperl/ppport.h new file mode 100644 index 0000000..8ec0d5f --- /dev/null +++ b/kvperl/ppport.h @@ -0,0 +1,7063 @@ +#if 0 +<<'SKIP'; +#endif +/* +---------------------------------------------------------------------- + + ppport.h -- Perl/Pollution/Portability Version 3.19 + + Automatically created by Devel::PPPort running under perl 5.010001. + + Do NOT edit this file directly! -- Edit PPPort_pm.PL and the + includes in parts/inc/ instead. + + Use 'perldoc ppport.h' to view the documentation below. + +---------------------------------------------------------------------- + +SKIP + +=pod + +=head1 NAME + +ppport.h - Perl/Pollution/Portability version 3.19 + +=head1 SYNOPSIS + + perl ppport.h [options] [source files] + + Searches current directory for files if no [source files] are given + + --help show short help + + --version show version + + --patch=file write one patch file with changes + --copy=suffix write changed copies with suffix + --diff=program use diff program and options + + --compat-version=version provide compatibility with Perl version + --cplusplus accept C++ comments + + --quiet don't output anything except fatal errors + --nodiag don't show diagnostics + --nohints don't show hints + --nochanges don't suggest changes + --nofilter don't filter input files + + --strip strip all script and doc functionality from + ppport.h + + --list-provided list provided API + --list-unsupported list unsupported API + --api-info=name show Perl API portability information + +=head1 COMPATIBILITY + +This version of F is designed to support operation with Perl +installations back to 5.003, and has been tested up to 5.10.0. + +=head1 OPTIONS + +=head2 --help + +Display a brief usage summary. + +=head2 --version + +Display the version of F. + +=head2 --patch=I + +If this option is given, a single patch file will be created if +any changes are suggested. This requires a working diff program +to be installed on your system. + +=head2 --copy=I + +If this option is given, a copy of each file will be saved with +the given suffix that contains the suggested changes. This does +not require any external programs. Note that this does not +automagially add a dot between the original filename and the +suffix. If you want the dot, you have to include it in the option +argument. + +If neither C<--patch> or C<--copy> are given, the default is to +simply print the diffs for each file. This requires either +C or a C program to be installed. + +=head2 --diff=I + +Manually set the diff program and options to use. The default +is to use C, when installed, and output unified +context diffs. + +=head2 --compat-version=I + +Tell F to check for compatibility with the given +Perl version. The default is to check for compatibility with Perl +version 5.003. You can use this option to reduce the output +of F if you intend to be backward compatible only +down to a certain Perl version. + +=head2 --cplusplus + +Usually, F will detect C++ style comments and +replace them with C style comments for portability reasons. +Using this option instructs F to leave C++ +comments untouched. + +=head2 --quiet + +Be quiet. Don't print anything except fatal errors. + +=head2 --nodiag + +Don't output any diagnostic messages. Only portability +alerts will be printed. + +=head2 --nohints + +Don't output any hints. Hints often contain useful portability +notes. Warnings will still be displayed. + +=head2 --nochanges + +Don't suggest any changes. Only give diagnostic output and hints +unless these are also deactivated. + +=head2 --nofilter + +Don't filter the list of input files. By default, files not looking +like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped. + +=head2 --strip + +Strip all script and documentation functionality from F. +This reduces the size of F dramatically and may be useful +if you want to include F in smaller modules without +increasing their distribution size too much. + +The stripped F will have a C<--unstrip> option that allows +you to undo the stripping, but only if an appropriate C +module is installed. + +=head2 --list-provided + +Lists the API elements for which compatibility is provided by +F. Also lists if it must be explicitly requested, +if it has dependencies, and if there are hints or warnings for it. + +=head2 --list-unsupported + +Lists the API elements that are known not to be supported by +F and below which version of Perl they probably +won't be available or work. + +=head2 --api-info=I + +Show portability information for API elements matching I. +If I is surrounded by slashes, it is interpreted as a regular +expression. + +=head1 DESCRIPTION + +In order for a Perl extension (XS) module to be as portable as possible +across differing versions of Perl itself, certain steps need to be taken. + +=over 4 + +=item * + +Including this header is the first major one. This alone will give you +access to a large part of the Perl API that hasn't been available in +earlier Perl releases. Use + + perl ppport.h --list-provided + +to see which API elements are provided by ppport.h. + +=item * + +You should avoid using deprecated parts of the API. For example, using +global Perl variables without the C prefix is deprecated. Also, +some API functions used to have a C prefix. Using this form is +also deprecated. You can safely use the supported API, as F +will provide wrappers for older Perl versions. + +=item * + +If you use one of a few functions or variables that were not present in +earlier versions of Perl, and that can't be provided using a macro, you +have to explicitly request support for these functions by adding one or +more C<#define>s in your source code before the inclusion of F. + +These functions or variables will be marked C in the list shown +by C<--list-provided>. + +Depending on whether you module has a single or multiple files that +use such functions or variables, you want either C or global +variants. + +For a C function or variable (used only in a single source +file), use: + + #define NEED_function + #define NEED_variable + +For a global function or variable (used in multiple source files), +use: + + #define NEED_function_GLOBAL + #define NEED_variable_GLOBAL + +Note that you mustn't have more than one global request for the +same function or variable in your project. + + Function / Variable Static Request Global Request + ----------------------------------------------------------------------------------------- + PL_parser NEED_PL_parser NEED_PL_parser_GLOBAL + PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL + eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL + grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL + grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL + grok_number() NEED_grok_number NEED_grok_number_GLOBAL + grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL + grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL + load_module() NEED_load_module NEED_load_module_GLOBAL + my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL + my_sprintf() NEED_my_sprintf NEED_my_sprintf_GLOBAL + my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL + my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL + newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL + newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL + newSV_type() NEED_newSV_type NEED_newSV_type_GLOBAL + newSVpvn_flags() NEED_newSVpvn_flags NEED_newSVpvn_flags_GLOBAL + newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL + pv_display() NEED_pv_display NEED_pv_display_GLOBAL + pv_escape() NEED_pv_escape NEED_pv_escape_GLOBAL + pv_pretty() NEED_pv_pretty NEED_pv_pretty_GLOBAL + sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL + sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL + sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL + sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL + sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL + sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL + sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL + vload_module() NEED_vload_module NEED_vload_module_GLOBAL + vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL + warner() NEED_warner NEED_warner_GLOBAL + +To avoid namespace conflicts, you can change the namespace of the +explicitly exported functions / variables using the C +macro. Just C<#define> the macro before including C: + + #define DPPP_NAMESPACE MyOwnNamespace_ + #include "ppport.h" + +The default namespace is C. + +=back + +The good thing is that most of the above can be checked by running +F on your source code. See the next section for +details. + +=head1 EXAMPLES + +To verify whether F is needed for your module, whether you +should make any changes to your code, and whether any special defines +should be used, F can be run as a Perl script to check your +source code. Simply say: + + perl ppport.h + +The result will usually be a list of patches suggesting changes +that should at least be acceptable, if not necessarily the most +efficient solution, or a fix for all possible problems. + +If you know that your XS module uses features only available in +newer Perl releases, if you're aware that it uses C++ comments, +and if you want all suggestions as a single patch file, you could +use something like this: + + perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff + +If you only want your code to be scanned without any suggestions +for changes, use: + + perl ppport.h --nochanges + +You can specify a different C program or options, using +the C<--diff> option: + + perl ppport.h --diff='diff -C 10' + +This would output context diffs with 10 lines of context. + +If you want to create patched copies of your files instead, use: + + perl ppport.h --copy=.new + +To display portability information for the C function, +use: + + perl ppport.h --api-info=newSVpvn + +Since the argument to C<--api-info> can be a regular expression, +you can use + + perl ppport.h --api-info=/_nomg$/ + +to display portability information for all C<_nomg> functions or + + perl ppport.h --api-info=/./ + +to display information for all known API elements. + +=head1 BUGS + +If this version of F is causing failure during +the compilation of this module, please check if newer versions +of either this module or C are available on CPAN +before sending a bug report. + +If F was generated using the latest version of +C and is causing failure of this module, please +file a bug report using the CPAN Request Tracker at L. + +Please include the following information: + +=over 4 + +=item 1. + +The complete output from running "perl -V" + +=item 2. + +This file. + +=item 3. + +The name and version of the module you were trying to build. + +=item 4. + +A full log of the build that failed. + +=item 5. + +Any other information that you think could be relevant. + +=back + +For the latest version of this code, please get the C +module from CPAN. + +=head1 COPYRIGHT + +Version 3.x, Copyright (c) 2004-2009, Marcus Holland-Moritz. + +Version 2.x, Copyright (C) 2001, Paul Marquess. + +Version 1.x, Copyright (C) 1999, Kenneth Albanowski. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +See L. + +=cut + +use strict; + +# Disable broken TRIE-optimization +BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 } + +my $VERSION = 3.19; + +my %opt = ( + quiet => 0, + diag => 1, + hints => 1, + changes => 1, + cplusplus => 0, + filter => 1, + strip => 0, + version => 0, +); + +my($ppport) = $0 =~ /([\w.]+)$/; +my $LF = '(?:\r\n|[\r\n])'; # line feed +my $HS = "[ \t]"; # horizontal whitespace + +# Never use C comments in this file! +my $ccs = '/'.'*'; +my $cce = '*'.'/'; +my $rccs = quotemeta $ccs; +my $rcce = quotemeta $cce; + +eval { + require Getopt::Long; + Getopt::Long::GetOptions(\%opt, qw( + help quiet diag! filter! hints! changes! cplusplus strip version + patch=s copy=s diff=s compat-version=s + list-provided list-unsupported api-info=s + )) or usage(); +}; + +if ($@ and grep /^-/, @ARGV) { + usage() if "@ARGV" =~ /^--?h(?:elp)?$/; + die "Getopt::Long not found. Please don't use any options.\n"; +} + +if ($opt{version}) { + print "This is $0 $VERSION.\n"; + exit 0; +} + +usage() if $opt{help}; +strip() if $opt{strip}; + +if (exists $opt{'compat-version'}) { + my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) }; + if ($@) { + die "Invalid version number format: '$opt{'compat-version'}'\n"; + } + die "Only Perl 5 is supported\n" if $r != 5; + die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000; + $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s; +} +else { + $opt{'compat-version'} = 5; +} + +my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/ + ? ( $1 => { + ($2 ? ( base => $2 ) : ()), + ($3 ? ( todo => $3 ) : ()), + (index($4, 'v') >= 0 ? ( varargs => 1 ) : ()), + (index($4, 'p') >= 0 ? ( provided => 1 ) : ()), + (index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()), + } ) + : die "invalid spec: $_" } qw( +AvFILLp|5.004050||p +AvFILL||| +CLASS|||n +CPERLscope|5.005000||p +CX_CURPAD_SAVE||| +CX_CURPAD_SV||| +CopFILEAV|5.006000||p +CopFILEGV_set|5.006000||p +CopFILEGV|5.006000||p +CopFILESV|5.006000||p +CopFILE_set|5.006000||p +CopFILE|5.006000||p +CopSTASHPV_set|5.006000||p +CopSTASHPV|5.006000||p +CopSTASH_eq|5.006000||p +CopSTASH_set|5.006000||p +CopSTASH|5.006000||p +CopyD|5.009002||p +Copy||| +CvPADLIST||| +CvSTASH||| +CvWEAKOUTSIDE||| +DEFSV_set|5.011000||p +DEFSV|5.004050||p +END_EXTERN_C|5.005000||p +ENTER||| +ERRSV|5.004050||p +EXTEND||| +EXTERN_C|5.005000||p +F0convert|||n +FREETMPS||| +GIMME_V||5.004000|n +GIMME|||n +GROK_NUMERIC_RADIX|5.007002||p +G_ARRAY||| +G_DISCARD||| +G_EVAL||| +G_METHOD|5.006001||p +G_NOARGS||| +G_SCALAR||| +G_VOID||5.004000| +GetVars||| +GvSVn|5.009003||p +GvSV||| +Gv_AMupdate||| +HEf_SVKEY||5.004000| +HeHASH||5.004000| +HeKEY||5.004000| +HeKLEN||5.004000| +HePV||5.004000| +HeSVKEY_force||5.004000| +HeSVKEY_set||5.004000| +HeSVKEY||5.004000| +HeUTF8||5.011000| +HeVAL||5.004000| +HvNAMELEN_get|5.009003||p +HvNAME_get|5.009003||p +HvNAME||| +INT2PTR|5.006000||p +IN_LOCALE_COMPILETIME|5.007002||p +IN_LOCALE_RUNTIME|5.007002||p +IN_LOCALE|5.007002||p +IN_PERL_COMPILETIME|5.008001||p +IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p +IS_NUMBER_INFINITY|5.007002||p +IS_NUMBER_IN_UV|5.007002||p +IS_NUMBER_NAN|5.007003||p +IS_NUMBER_NEG|5.007002||p +IS_NUMBER_NOT_INT|5.007002||p +IVSIZE|5.006000||p +IVTYPE|5.006000||p +IVdf|5.006000||p +LEAVE||| +LVRET||| +MARK||| +MULTICALL||5.011000| +MY_CXT_CLONE|5.009002||p +MY_CXT_INIT|5.007003||p +MY_CXT|5.007003||p +MoveD|5.009002||p +Move||| +NOOP|5.005000||p +NUM2PTR|5.006000||p +NVTYPE|5.006000||p +NVef|5.006001||p +NVff|5.006001||p +NVgf|5.006001||p +Newxc|5.009003||p +Newxz|5.009003||p +Newx|5.009003||p +Nullav||| +Nullch||| +Nullcv||| +Nullhv||| +Nullsv||| +ORIGMARK||| +PAD_BASE_SV||| +PAD_CLONE_VARS||| +PAD_COMPNAME_FLAGS||| +PAD_COMPNAME_GEN_set||| +PAD_COMPNAME_GEN||| +PAD_COMPNAME_OURSTASH||| +PAD_COMPNAME_PV||| +PAD_COMPNAME_TYPE||| +PAD_DUP||| +PAD_RESTORE_LOCAL||| +PAD_SAVE_LOCAL||| +PAD_SAVE_SETNULLPAD||| +PAD_SETSV||| +PAD_SET_CUR_NOSAVE||| +PAD_SET_CUR||| +PAD_SVl||| +PAD_SV||| +PERLIO_FUNCS_CAST|5.009003||p +PERLIO_FUNCS_DECL|5.009003||p +PERL_ABS|5.008001||p +PERL_BCDVERSION|5.011000||p +PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p +PERL_HASH|5.004000||p +PERL_INT_MAX|5.004000||p +PERL_INT_MIN|5.004000||p +PERL_LONG_MAX|5.004000||p +PERL_LONG_MIN|5.004000||p +PERL_MAGIC_arylen|5.007002||p +PERL_MAGIC_backref|5.007002||p +PERL_MAGIC_bm|5.007002||p +PERL_MAGIC_collxfrm|5.007002||p +PERL_MAGIC_dbfile|5.007002||p +PERL_MAGIC_dbline|5.007002||p +PERL_MAGIC_defelem|5.007002||p +PERL_MAGIC_envelem|5.007002||p +PERL_MAGIC_env|5.007002||p +PERL_MAGIC_ext|5.007002||p +PERL_MAGIC_fm|5.007002||p +PERL_MAGIC_glob|5.011000||p +PERL_MAGIC_isaelem|5.007002||p +PERL_MAGIC_isa|5.007002||p +PERL_MAGIC_mutex|5.011000||p +PERL_MAGIC_nkeys|5.007002||p +PERL_MAGIC_overload_elem|5.007002||p +PERL_MAGIC_overload_table|5.007002||p +PERL_MAGIC_overload|5.007002||p +PERL_MAGIC_pos|5.007002||p +PERL_MAGIC_qr|5.007002||p +PERL_MAGIC_regdata|5.007002||p +PERL_MAGIC_regdatum|5.007002||p +PERL_MAGIC_regex_global|5.007002||p +PERL_MAGIC_shared_scalar|5.007003||p +PERL_MAGIC_shared|5.007003||p +PERL_MAGIC_sigelem|5.007002||p +PERL_MAGIC_sig|5.007002||p +PERL_MAGIC_substr|5.007002||p +PERL_MAGIC_sv|5.007002||p +PERL_MAGIC_taint|5.007002||p +PERL_MAGIC_tiedelem|5.007002||p +PERL_MAGIC_tiedscalar|5.007002||p +PERL_MAGIC_tied|5.007002||p +PERL_MAGIC_utf8|5.008001||p +PERL_MAGIC_uvar_elem|5.007003||p +PERL_MAGIC_uvar|5.007002||p +PERL_MAGIC_vec|5.007002||p +PERL_MAGIC_vstring|5.008001||p +PERL_PV_ESCAPE_ALL|5.009004||p +PERL_PV_ESCAPE_FIRSTCHAR|5.009004||p +PERL_PV_ESCAPE_NOBACKSLASH|5.009004||p +PERL_PV_ESCAPE_NOCLEAR|5.009004||p +PERL_PV_ESCAPE_QUOTE|5.009004||p +PERL_PV_ESCAPE_RE|5.009005||p +PERL_PV_ESCAPE_UNI_DETECT|5.009004||p +PERL_PV_ESCAPE_UNI|5.009004||p +PERL_PV_PRETTY_DUMP|5.009004||p +PERL_PV_PRETTY_ELLIPSES|5.010000||p +PERL_PV_PRETTY_LTGT|5.009004||p +PERL_PV_PRETTY_NOCLEAR|5.010000||p +PERL_PV_PRETTY_QUOTE|5.009004||p +PERL_PV_PRETTY_REGPROP|5.009004||p +PERL_QUAD_MAX|5.004000||p +PERL_QUAD_MIN|5.004000||p +PERL_REVISION|5.006000||p +PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p +PERL_SCAN_DISALLOW_PREFIX|5.007003||p +PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p +PERL_SCAN_SILENT_ILLDIGIT|5.008001||p +PERL_SHORT_MAX|5.004000||p +PERL_SHORT_MIN|5.004000||p +PERL_SIGNALS_UNSAFE_FLAG|5.008001||p +PERL_SUBVERSION|5.006000||p +PERL_SYS_INIT3||5.006000| +PERL_SYS_INIT||| +PERL_SYS_TERM||5.011000| +PERL_UCHAR_MAX|5.004000||p +PERL_UCHAR_MIN|5.004000||p +PERL_UINT_MAX|5.004000||p +PERL_UINT_MIN|5.004000||p +PERL_ULONG_MAX|5.004000||p +PERL_ULONG_MIN|5.004000||p +PERL_UNUSED_ARG|5.009003||p +PERL_UNUSED_CONTEXT|5.009004||p +PERL_UNUSED_DECL|5.007002||p +PERL_UNUSED_VAR|5.007002||p +PERL_UQUAD_MAX|5.004000||p +PERL_UQUAD_MIN|5.004000||p +PERL_USE_GCC_BRACE_GROUPS|5.009004||p +PERL_USHORT_MAX|5.004000||p +PERL_USHORT_MIN|5.004000||p +PERL_VERSION|5.006000||p +PL_DBsignal|5.005000||p +PL_DBsingle|||pn +PL_DBsub|||pn +PL_DBtrace|||pn +PL_Sv|5.005000||p +PL_bufend|5.011000||p +PL_bufptr|5.011000||p +PL_compiling|5.004050||p +PL_copline|5.011000||p +PL_curcop|5.004050||p +PL_curstash|5.004050||p +PL_debstash|5.004050||p +PL_defgv|5.004050||p +PL_diehook|5.004050||p +PL_dirty|5.004050||p +PL_dowarn|||pn +PL_errgv|5.004050||p +PL_error_count|5.011000||p +PL_expect|5.011000||p +PL_hexdigit|5.005000||p +PL_hints|5.005000||p +PL_in_my_stash|5.011000||p +PL_in_my|5.011000||p +PL_last_in_gv|||n +PL_laststatval|5.005000||p +PL_lex_state|5.011000||p +PL_lex_stuff|5.011000||p +PL_linestr|5.011000||p +PL_modglobal||5.005000|n +PL_na|5.004050||pn +PL_no_modify|5.006000||p +PL_ofsgv|||n +PL_parser|5.009005||p +PL_perl_destruct_level|5.004050||p +PL_perldb|5.004050||p +PL_ppaddr|5.006000||p +PL_rsfp_filters|5.004050||p +PL_rsfp|5.004050||p +PL_rs|||n +PL_signals|5.008001||p +PL_stack_base|5.004050||p +PL_stack_sp|5.004050||p +PL_statcache|5.005000||p +PL_stdingv|5.004050||p +PL_sv_arenaroot|5.004050||p +PL_sv_no|5.004050||pn +PL_sv_undef|5.004050||pn +PL_sv_yes|5.004050||pn +PL_tainted|5.004050||p +PL_tainting|5.004050||p +PL_tokenbuf|5.011000||p +POP_MULTICALL||5.011000| +POPi|||n +POPl|||n +POPn|||n +POPpbytex||5.007001|n +POPpx||5.005030|n +POPp|||n +POPs|||n +PTR2IV|5.006000||p +PTR2NV|5.006000||p +PTR2UV|5.006000||p +PTR2nat|5.009003||p +PTR2ul|5.007001||p +PTRV|5.006000||p +PUSHMARK||| +PUSH_MULTICALL||5.011000| +PUSHi||| +PUSHmortal|5.009002||p +PUSHn||| +PUSHp||| +PUSHs||| +PUSHu|5.004000||p +PUTBACK||| +PerlIO_clearerr||5.007003| +PerlIO_close||5.007003| +PerlIO_context_layers||5.009004| +PerlIO_eof||5.007003| +PerlIO_error||5.007003| +PerlIO_fileno||5.007003| +PerlIO_fill||5.007003| +PerlIO_flush||5.007003| +PerlIO_get_base||5.007003| +PerlIO_get_bufsiz||5.007003| +PerlIO_get_cnt||5.007003| +PerlIO_get_ptr||5.007003| +PerlIO_read||5.007003| +PerlIO_seek||5.007003| +PerlIO_set_cnt||5.007003| +PerlIO_set_ptrcnt||5.007003| +PerlIO_setlinebuf||5.007003| +PerlIO_stderr||5.007003| +PerlIO_stdin||5.007003| +PerlIO_stdout||5.007003| +PerlIO_tell||5.007003| +PerlIO_unread||5.007003| +PerlIO_write||5.007003| +Perl_signbit||5.009005|n +PoisonFree|5.009004||p +PoisonNew|5.009004||p +PoisonWith|5.009004||p +Poison|5.008000||p +RETVAL|||n +Renewc||| +Renew||| +SAVECLEARSV||| +SAVECOMPPAD||| +SAVEPADSV||| +SAVETMPS||| +SAVE_DEFSV|5.004050||p +SPAGAIN||| +SP||| +START_EXTERN_C|5.005000||p +START_MY_CXT|5.007003||p +STMT_END|||p +STMT_START|||p +STR_WITH_LEN|5.009003||p +ST||| +SV_CONST_RETURN|5.009003||p +SV_COW_DROP_PV|5.008001||p +SV_COW_SHARED_HASH_KEYS|5.009005||p +SV_GMAGIC|5.007002||p +SV_HAS_TRAILING_NUL|5.009004||p +SV_IMMEDIATE_UNREF|5.007001||p +SV_MUTABLE_RETURN|5.009003||p +SV_NOSTEAL|5.009002||p +SV_SMAGIC|5.009003||p +SV_UTF8_NO_ENCODING|5.008001||p +SVfARG|5.009005||p +SVf_UTF8|5.006000||p +SVf|5.006000||p +SVt_IV||| +SVt_NV||| +SVt_PVAV||| +SVt_PVCV||| +SVt_PVHV||| +SVt_PVMG||| +SVt_PV||| +Safefree||| +Slab_Alloc||| +Slab_Free||| +Slab_to_rw||| +StructCopy||| +SvCUR_set||| +SvCUR||| +SvEND||| +SvGAMAGIC||5.006001| +SvGETMAGIC|5.004050||p +SvGROW||| +SvIOK_UV||5.006000| +SvIOK_notUV||5.006000| +SvIOK_off||| +SvIOK_only_UV||5.006000| +SvIOK_only||| +SvIOK_on||| +SvIOKp||| +SvIOK||| +SvIVX||| +SvIV_nomg|5.009001||p +SvIV_set||| +SvIVx||| +SvIV||| +SvIsCOW_shared_hash||5.008003| +SvIsCOW||5.008003| +SvLEN_set||| +SvLEN||| +SvLOCK||5.007003| +SvMAGIC_set|5.009003||p +SvNIOK_off||| +SvNIOKp||| +SvNIOK||| +SvNOK_off||| +SvNOK_only||| +SvNOK_on||| +SvNOKp||| +SvNOK||| +SvNVX||| +SvNV_set||| +SvNVx||| +SvNV||| +SvOK||| +SvOOK_offset||5.011000| +SvOOK||| +SvPOK_off||| +SvPOK_only_UTF8||5.006000| +SvPOK_only||| +SvPOK_on||| +SvPOKp||| +SvPOK||| +SvPVX_const|5.009003||p +SvPVX_mutable|5.009003||p +SvPVX||| +SvPV_const|5.009003||p +SvPV_flags_const_nolen|5.009003||p +SvPV_flags_const|5.009003||p +SvPV_flags_mutable|5.009003||p +SvPV_flags|5.007002||p +SvPV_force_flags_mutable|5.009003||p +SvPV_force_flags_nolen|5.009003||p +SvPV_force_flags|5.007002||p +SvPV_force_mutable|5.009003||p +SvPV_force_nolen|5.009003||p +SvPV_force_nomg_nolen|5.009003||p +SvPV_force_nomg|5.007002||p +SvPV_force|||p +SvPV_mutable|5.009003||p +SvPV_nolen_const|5.009003||p +SvPV_nolen|5.006000||p +SvPV_nomg_const_nolen|5.009003||p +SvPV_nomg_const|5.009003||p +SvPV_nomg|5.007002||p +SvPV_renew|5.009003||p +SvPV_set||| +SvPVbyte_force||5.009002| +SvPVbyte_nolen||5.006000| +SvPVbytex_force||5.006000| +SvPVbytex||5.006000| +SvPVbyte|5.006000||p +SvPVutf8_force||5.006000| +SvPVutf8_nolen||5.006000| +SvPVutf8x_force||5.006000| +SvPVutf8x||5.006000| +SvPVutf8||5.006000| +SvPVx||| +SvPV||| +SvREFCNT_dec||| +SvREFCNT_inc_NN|5.009004||p +SvREFCNT_inc_simple_NN|5.009004||p +SvREFCNT_inc_simple_void_NN|5.009004||p +SvREFCNT_inc_simple_void|5.009004||p +SvREFCNT_inc_simple|5.009004||p +SvREFCNT_inc_void_NN|5.009004||p +SvREFCNT_inc_void|5.009004||p +SvREFCNT_inc|||p +SvREFCNT||| +SvROK_off||| +SvROK_on||| +SvROK||| +SvRV_set|5.009003||p +SvRV||| +SvRXOK||5.009005| +SvRX||5.009005| +SvSETMAGIC||| +SvSHARED_HASH|5.009003||p +SvSHARE||5.007003| +SvSTASH_set|5.009003||p +SvSTASH||| +SvSetMagicSV_nosteal||5.004000| +SvSetMagicSV||5.004000| +SvSetSV_nosteal||5.004000| +SvSetSV||| +SvTAINTED_off||5.004000| +SvTAINTED_on||5.004000| +SvTAINTED||5.004000| +SvTAINT||| +SvTRUE||| +SvTYPE||| +SvUNLOCK||5.007003| +SvUOK|5.007001|5.006000|p +SvUPGRADE||| +SvUTF8_off||5.006000| +SvUTF8_on||5.006000| +SvUTF8||5.006000| +SvUVXx|5.004000||p +SvUVX|5.004000||p +SvUV_nomg|5.009001||p +SvUV_set|5.009003||p +SvUVx|5.004000||p +SvUV|5.004000||p +SvVOK||5.008001| +SvVSTRING_mg|5.009004||p +THIS|||n +UNDERBAR|5.009002||p +UTF8_MAXBYTES|5.009002||p +UVSIZE|5.006000||p +UVTYPE|5.006000||p +UVXf|5.007001||p +UVof|5.006000||p +UVuf|5.006000||p +UVxf|5.006000||p +WARN_ALL|5.006000||p +WARN_AMBIGUOUS|5.006000||p +WARN_ASSERTIONS|5.011000||p +WARN_BAREWORD|5.006000||p +WARN_CLOSED|5.006000||p +WARN_CLOSURE|5.006000||p +WARN_DEBUGGING|5.006000||p +WARN_DEPRECATED|5.006000||p +WARN_DIGIT|5.006000||p +WARN_EXEC|5.006000||p +WARN_EXITING|5.006000||p +WARN_GLOB|5.006000||p +WARN_INPLACE|5.006000||p +WARN_INTERNAL|5.006000||p +WARN_IO|5.006000||p +WARN_LAYER|5.008000||p +WARN_MALLOC|5.006000||p +WARN_MISC|5.006000||p +WARN_NEWLINE|5.006000||p +WARN_NUMERIC|5.006000||p +WARN_ONCE|5.006000||p +WARN_OVERFLOW|5.006000||p +WARN_PACK|5.006000||p +WARN_PARENTHESIS|5.006000||p +WARN_PIPE|5.006000||p +WARN_PORTABLE|5.006000||p +WARN_PRECEDENCE|5.006000||p +WARN_PRINTF|5.006000||p +WARN_PROTOTYPE|5.006000||p +WARN_QW|5.006000||p +WARN_RECURSION|5.006000||p +WARN_REDEFINE|5.006000||p +WARN_REGEXP|5.006000||p +WARN_RESERVED|5.006000||p +WARN_SEMICOLON|5.006000||p +WARN_SEVERE|5.006000||p +WARN_SIGNAL|5.006000||p +WARN_SUBSTR|5.006000||p +WARN_SYNTAX|5.006000||p +WARN_TAINT|5.006000||p +WARN_THREADS|5.008000||p +WARN_UNINITIALIZED|5.006000||p +WARN_UNOPENED|5.006000||p +WARN_UNPACK|5.006000||p +WARN_UNTIE|5.006000||p +WARN_UTF8|5.006000||p +WARN_VOID|5.006000||p +XCPT_CATCH|5.009002||p +XCPT_RETHROW|5.009002||p +XCPT_TRY_END|5.009002||p +XCPT_TRY_START|5.009002||p +XPUSHi||| +XPUSHmortal|5.009002||p +XPUSHn||| +XPUSHp||| +XPUSHs||| +XPUSHu|5.004000||p +XSPROTO|5.010000||p +XSRETURN_EMPTY||| +XSRETURN_IV||| +XSRETURN_NO||| +XSRETURN_NV||| +XSRETURN_PV||| +XSRETURN_UNDEF||| +XSRETURN_UV|5.008001||p +XSRETURN_YES||| +XSRETURN|||p +XST_mIV||| +XST_mNO||| +XST_mNV||| +XST_mPV||| +XST_mUNDEF||| +XST_mUV|5.008001||p +XST_mYES||| +XS_VERSION_BOOTCHECK||| +XS_VERSION||| +XSprePUSH|5.006000||p +XS||| +ZeroD|5.009002||p +Zero||| +_aMY_CXT|5.007003||p +_pMY_CXT|5.007003||p +aMY_CXT_|5.007003||p +aMY_CXT|5.007003||p +aTHXR_|5.011000||p +aTHXR|5.011000||p +aTHX_|5.006000||p +aTHX|5.006000||p +add_data|||n +addmad||| +allocmy||| +amagic_call||| +amagic_cmp_locale||| +amagic_cmp||| +amagic_i_ncmp||| +amagic_ncmp||| +any_dup||| +ao||| +append_elem||| +append_list||| +append_madprops||| +apply_attrs_my||| +apply_attrs_string||5.006001| +apply_attrs||| +apply||| +atfork_lock||5.007003|n +atfork_unlock||5.007003|n +av_arylen_p||5.009003| +av_clear||| +av_create_and_push||5.009005| +av_create_and_unshift_one||5.009005| +av_delete||5.006000| +av_exists||5.006000| +av_extend||| +av_fetch||| +av_fill||| +av_iter_p||5.011000| +av_len||| +av_make||| +av_pop||| +av_push||| +av_reify||| +av_shift||| +av_store||| +av_undef||| +av_unshift||| +ax|||n +bad_type||| +bind_match||| +block_end||| +block_gimme||5.004000| +block_start||| +boolSV|5.004000||p +boot_core_PerlIO||| +boot_core_UNIVERSAL||| +boot_core_mro||| +bytes_from_utf8||5.007001| +bytes_to_uni|||n +bytes_to_utf8||5.006001| +call_argv|5.006000||p +call_atexit||5.006000| +call_list||5.004000| +call_method|5.006000||p +call_pv|5.006000||p +call_sv|5.006000||p +calloc||5.007002|n +cando||| +cast_i32||5.006000| +cast_iv||5.006000| +cast_ulong||5.006000| +cast_uv||5.006000| +check_type_and_open||| +check_uni||| +checkcomma||| +checkposixcc||| +ckWARN|5.006000||p +ck_anoncode||| +ck_bitop||| +ck_concat||| +ck_defined||| +ck_delete||| +ck_die||| +ck_each||| +ck_eof||| +ck_eval||| +ck_exec||| +ck_exists||| +ck_exit||| +ck_ftst||| +ck_fun||| +ck_glob||| +ck_grep||| +ck_index||| +ck_join||| +ck_lfun||| +ck_listiob||| +ck_match||| +ck_method||| +ck_null||| +ck_open||| +ck_readline||| +ck_repeat||| +ck_require||| +ck_return||| +ck_rfun||| +ck_rvconst||| +ck_sassign||| +ck_select||| +ck_shift||| +ck_sort||| +ck_spair||| +ck_split||| +ck_subr||| +ck_substr||| +ck_svconst||| +ck_trunc||| +ck_unpack||| +ckwarn_d||5.009003| +ckwarn||5.009003| +cl_and|||n +cl_anything|||n +cl_init_zero|||n +cl_init|||n +cl_is_anything|||n +cl_or|||n +clear_placeholders||| +closest_cop||| +convert||| +cop_free||| +cr_textfilter||| +create_eval_scope||| +croak_nocontext|||vn +croak_xs_usage||5.011000| +croak|||v +csighandler||5.009003|n +curmad||| +custom_op_desc||5.007003| +custom_op_name||5.007003| +cv_ckproto_len||| +cv_clone||| +cv_const_sv||5.004000| +cv_dump||| +cv_undef||| +cx_dump||5.005000| +cx_dup||| +cxinc||| +dAXMARK|5.009003||p +dAX|5.007002||p +dITEMS|5.007002||p +dMARK||| +dMULTICALL||5.009003| +dMY_CXT_SV|5.007003||p +dMY_CXT|5.007003||p +dNOOP|5.006000||p +dORIGMARK||| +dSP||| +dTHR|5.004050||p +dTHXR|5.011000||p +dTHXa|5.006000||p +dTHXoa|5.006000||p +dTHX|5.006000||p +dUNDERBAR|5.009002||p +dVAR|5.009003||p +dXCPT|5.009002||p +dXSARGS||| +dXSI32||| +dXSTARG|5.006000||p +deb_curcv||| +deb_nocontext|||vn +deb_stack_all||| +deb_stack_n||| +debop||5.005000| +debprofdump||5.005000| +debprof||| +debstackptrs||5.007003| +debstack||5.007003| +debug_start_match||| +deb||5.007003|v +del_sv||| +delete_eval_scope||| +delimcpy||5.004000| +deprecate_old||| +deprecate||| +despatch_signals||5.007001| +destroy_matcher||| +die_nocontext|||vn +die_where||| +die|||v +dirp_dup||| +div128||| +djSP||| +do_aexec5||| +do_aexec||| +do_aspawn||| +do_binmode||5.004050| +do_chomp||| +do_chop||| +do_close||| +do_dump_pad||| +do_eof||| +do_exec3||| +do_execfree||| +do_exec||| +do_gv_dump||5.006000| +do_gvgv_dump||5.006000| +do_hv_dump||5.006000| +do_ipcctl||| +do_ipcget||| +do_join||| +do_kv||| +do_magic_dump||5.006000| +do_msgrcv||| +do_msgsnd||| +do_oddball||| +do_op_dump||5.006000| +do_op_xmldump||| +do_open9||5.006000| +do_openn||5.007001| +do_open||5.004000| +do_pmop_dump||5.006000| +do_pmop_xmldump||| +do_print||| +do_readline||| +do_seek||| +do_semop||| +do_shmio||| +do_smartmatch||| +do_spawn_nowait||| +do_spawn||| +do_sprintf||| +do_sv_dump||5.006000| +do_sysseek||| +do_tell||| +do_trans_complex_utf8||| +do_trans_complex||| +do_trans_count_utf8||| +do_trans_count||| +do_trans_simple_utf8||| +do_trans_simple||| +do_trans||| +do_vecget||| +do_vecset||| +do_vop||| +docatch||| +doeval||| +dofile||| +dofindlabel||| +doform||| +doing_taint||5.008001|n +dooneliner||| +doopen_pm||| +doparseform||| +dopoptoeval||| +dopoptogiven||| +dopoptolabel||| +dopoptoloop||| +dopoptosub_at||| +dopoptowhen||| +doref||5.009003| +dounwind||| +dowantarray||| +dump_all||5.006000| +dump_eval||5.006000| +dump_exec_pos||| +dump_fds||| +dump_form||5.006000| +dump_indent||5.006000|v +dump_mstats||| +dump_packsubs||5.006000| +dump_sub||5.006000| +dump_sv_child||| +dump_trie_interim_list||| +dump_trie_interim_table||| +dump_trie||| +dump_vindent||5.006000| +dumpuntil||| +dup_attrlist||| +emulate_cop_io||| +eval_pv|5.006000||p +eval_sv|5.006000||p +exec_failed||| +expect_number||| +fbm_compile||5.005000| +fbm_instr||5.005000| +feature_is_enabled||| +fetch_cop_label||5.011000| +filter_add||| +filter_del||| +filter_gets||| +filter_read||| +find_and_forget_pmops||| +find_array_subscript||| +find_beginning||| +find_byclass||| +find_hash_subscript||| +find_in_my_stash||| +find_runcv||5.008001| +find_rundefsvoffset||5.009002| +find_script||| +find_uninit_var||| +first_symbol|||n +fold_constants||| +forbid_setid||| +force_ident||| +force_list||| +force_next||| +force_version||| +force_word||| +forget_pmop||| +form_nocontext|||vn +form||5.004000|v +fp_dup||| +fprintf_nocontext|||vn +free_global_struct||| +free_tied_hv_pool||| +free_tmps||| +gen_constant_list||| +get_arena||| +get_aux_mg||| +get_av|5.006000||p +get_context||5.006000|n +get_cvn_flags||5.009005| +get_cv|5.006000||p +get_db_sub||| +get_debug_opts||| +get_hash_seed||| +get_hv|5.006000||p +get_isa_hash||| +get_mstats||| +get_no_modify||| +get_num||| +get_op_descs||5.005000| +get_op_names||5.005000| +get_opargs||| +get_ppaddr||5.006000| +get_re_arg||| +get_sv|5.006000||p +get_vtbl||5.005030| +getcwd_sv||5.007002| +getenv_len||| +glob_2number||| +glob_assign_glob||| +glob_assign_ref||| +gp_dup||| +gp_free||| +gp_ref||| +grok_bin|5.007003||p +grok_hex|5.007003||p +grok_number|5.007002||p +grok_numeric_radix|5.007002||p +grok_oct|5.007003||p +group_end||| +gv_AVadd||| +gv_HVadd||| +gv_IOadd||| +gv_SVadd||| +gv_autoload4||5.004000| +gv_check||| +gv_const_sv||5.009003| +gv_dump||5.006000| +gv_efullname3||5.004000| +gv_efullname4||5.006001| +gv_efullname||| +gv_ename||| +gv_fetchfile_flags||5.009005| +gv_fetchfile||| +gv_fetchmeth_autoload||5.007003| +gv_fetchmethod_autoload||5.004000| +gv_fetchmethod_flags||5.011000| +gv_fetchmethod||| +gv_fetchmeth||| +gv_fetchpvn_flags|5.009002||p +gv_fetchpvs|5.009004||p +gv_fetchpv||| +gv_fetchsv||5.009002| +gv_fullname3||5.004000| +gv_fullname4||5.006001| +gv_fullname||| +gv_get_super_pkg||| +gv_handler||5.007001| +gv_init_sv||| +gv_init||| +gv_name_set||5.009004| +gv_stashpvn|5.004000||p +gv_stashpvs|5.009003||p +gv_stashpv||| +gv_stashsv||| +he_dup||| +hek_dup||| +hfreeentries||| +hsplit||| +hv_assert||5.011000| +hv_auxinit|||n +hv_backreferences_p||| +hv_clear_placeholders||5.009001| +hv_clear||| +hv_common_key_len||5.010000| +hv_common||5.010000| +hv_copy_hints_hv||| +hv_delayfree_ent||5.004000| +hv_delete_common||| +hv_delete_ent||5.004000| +hv_delete||| +hv_eiter_p||5.009003| +hv_eiter_set||5.009003| +hv_exists_ent||5.004000| +hv_exists||| +hv_fetch_ent||5.004000| +hv_fetchs|5.009003||p +hv_fetch||| +hv_free_ent||5.004000| +hv_iterinit||| +hv_iterkeysv||5.004000| +hv_iterkey||| +hv_iternext_flags||5.008000| +hv_iternextsv||| +hv_iternext||| +hv_iterval||| +hv_kill_backrefs||| +hv_ksplit||5.004000| +hv_magic_check|||n +hv_magic||| +hv_name_set||5.009003| +hv_notallowed||| +hv_placeholders_get||5.009003| +hv_placeholders_p||5.009003| +hv_placeholders_set||5.009003| +hv_riter_p||5.009003| +hv_riter_set||5.009003| +hv_scalar||5.009001| +hv_store_ent||5.004000| +hv_store_flags||5.008000| +hv_stores|5.009004||p +hv_store||| +hv_undef||| +ibcmp_locale||5.004000| +ibcmp_utf8||5.007003| +ibcmp||| +incline||| +incpush_if_exists||| +incpush_use_sep||| +incpush||| +ingroup||| +init_argv_symbols||| +init_debugger||| +init_global_struct||| +init_i18nl10n||5.006000| +init_i18nl14n||5.006000| +init_ids||| +init_interp||| +init_main_stash||| +init_perllib||| +init_postdump_symbols||| +init_predump_symbols||| +init_stacks||5.005000| +init_tm||5.007002| +instr||| +intro_my||| +intuit_method||| +intuit_more||| +invert||| +io_close||| +isALNUMC|5.006000||p +isALNUM||| +isALPHA||| +isASCII|5.006000||p +isBLANK|5.006001||p +isCNTRL|5.006000||p +isDIGIT||| +isGRAPH|5.006000||p +isGV_with_GP|5.009004||p +isLOWER||| +isPRINT|5.004000||p +isPSXSPC|5.006001||p +isPUNCT|5.006000||p +isSPACE||| +isUPPER||| +isXDIGIT|5.006000||p +is_an_int||| +is_gv_magical_sv||| +is_handle_constructor|||n +is_list_assignment||| +is_lvalue_sub||5.007001| +is_uni_alnum_lc||5.006000| +is_uni_alnumc_lc||5.006000| +is_uni_alnumc||5.006000| +is_uni_alnum||5.006000| +is_uni_alpha_lc||5.006000| +is_uni_alpha||5.006000| +is_uni_ascii_lc||5.006000| +is_uni_ascii||5.006000| +is_uni_cntrl_lc||5.006000| +is_uni_cntrl||5.006000| +is_uni_digit_lc||5.006000| +is_uni_digit||5.006000| +is_uni_graph_lc||5.006000| +is_uni_graph||5.006000| +is_uni_idfirst_lc||5.006000| +is_uni_idfirst||5.006000| +is_uni_lower_lc||5.006000| +is_uni_lower||5.006000| +is_uni_print_lc||5.006000| +is_uni_print||5.006000| +is_uni_punct_lc||5.006000| +is_uni_punct||5.006000| +is_uni_space_lc||5.006000| +is_uni_space||5.006000| +is_uni_upper_lc||5.006000| +is_uni_upper||5.006000| +is_uni_xdigit_lc||5.006000| +is_uni_xdigit||5.006000| +is_utf8_alnumc||5.006000| +is_utf8_alnum||5.006000| +is_utf8_alpha||5.006000| +is_utf8_ascii||5.006000| +is_utf8_char_slow|||n +is_utf8_char||5.006000| +is_utf8_cntrl||5.006000| +is_utf8_common||| +is_utf8_digit||5.006000| +is_utf8_graph||5.006000| +is_utf8_idcont||5.008000| +is_utf8_idfirst||5.006000| +is_utf8_lower||5.006000| +is_utf8_mark||5.006000| +is_utf8_print||5.006000| +is_utf8_punct||5.006000| +is_utf8_space||5.006000| +is_utf8_string_loclen||5.009003| +is_utf8_string_loc||5.008001| +is_utf8_string||5.006001| +is_utf8_upper||5.006000| +is_utf8_xdigit||5.006000| +isa_lookup||| +items|||n +ix|||n +jmaybe||| +join_exact||| +keyword||| +leave_scope||| +lex_end||| +lex_start||| +linklist||| +listkids||| +list||| +load_module_nocontext|||vn +load_module|5.006000||pv +localize||| +looks_like_bool||| +looks_like_number||| +lop||| +mPUSHi|5.009002||p +mPUSHn|5.009002||p +mPUSHp|5.009002||p +mPUSHs|5.011000||p +mPUSHu|5.009002||p +mXPUSHi|5.009002||p +mXPUSHn|5.009002||p +mXPUSHp|5.009002||p +mXPUSHs|5.011000||p +mXPUSHu|5.009002||p +mad_free||| +madlex||| +madparse||| +magic_clear_all_env||| +magic_clearenv||| +magic_clearhint||| +magic_clearisa||| +magic_clearpack||| +magic_clearsig||| +magic_dump||5.006000| +magic_existspack||| +magic_freearylen_p||| +magic_freeovrld||| +magic_getarylen||| +magic_getdefelem||| +magic_getnkeys||| +magic_getpack||| +magic_getpos||| +magic_getsig||| +magic_getsubstr||| +magic_gettaint||| +magic_getuvar||| +magic_getvec||| +magic_get||| +magic_killbackrefs||| +magic_len||| +magic_methcall||| +magic_methpack||| +magic_nextpack||| +magic_regdata_cnt||| +magic_regdatum_get||| +magic_regdatum_set||| +magic_scalarpack||| +magic_set_all_env||| +magic_setamagic||| +magic_setarylen||| +magic_setcollxfrm||| +magic_setdbline||| +magic_setdefelem||| +magic_setenv||| +magic_sethint||| +magic_setisa||| +magic_setmglob||| +magic_setnkeys||| +magic_setpack||| +magic_setpos||| +magic_setregexp||| +magic_setsig||| +magic_setsubstr||| +magic_settaint||| +magic_setutf8||| +magic_setuvar||| +magic_setvec||| +magic_set||| +magic_sizepack||| +magic_wipepack||| +make_matcher||| +make_trie_failtable||| +make_trie||| +malloc_good_size|||n +malloced_size|||n +malloc||5.007002|n +markstack_grow||| +matcher_matches_sv||| +measure_struct||| +memEQ|5.004000||p +memNE|5.004000||p +mem_collxfrm||| +mem_log_common|||n +mess_alloc||| +mess_nocontext|||vn +mess||5.006000|v +method_common||| +mfree||5.007002|n +mg_clear||| +mg_copy||| +mg_dup||| +mg_find||| +mg_free||| +mg_get||| +mg_length||5.005000| +mg_localize||| +mg_magical||| +mg_set||| +mg_size||5.005000| +mini_mktime||5.007002| +missingterm||| +mode_from_discipline||| +modkids||| +mod||| +more_bodies||| +more_sv||| +moreswitches||| +mro_get_from_name||5.011000| +mro_get_linear_isa_dfs||| +mro_get_linear_isa||5.009005| +mro_get_private_data||5.011000| +mro_isa_changed_in||| +mro_meta_dup||| +mro_meta_init||| +mro_method_changed_in||5.009005| +mro_register||5.011000| +mro_set_mro||5.011000| +mro_set_private_data||5.011000| +mul128||| +mulexp10|||n +my_atof2||5.007002| +my_atof||5.006000| +my_attrs||| +my_bcopy|||n +my_betoh16|||n +my_betoh32|||n +my_betoh64|||n +my_betohi|||n +my_betohl|||n +my_betohs|||n +my_bzero|||n +my_chsize||| +my_clearenv||| +my_cxt_index||| +my_cxt_init||| +my_dirfd||5.009005| +my_exit_jump||| +my_exit||| +my_failure_exit||5.004000| +my_fflush_all||5.006000| +my_fork||5.007003|n +my_htobe16|||n +my_htobe32|||n +my_htobe64|||n +my_htobei|||n +my_htobel|||n +my_htobes|||n +my_htole16|||n +my_htole32|||n +my_htole64|||n +my_htolei|||n +my_htolel|||n +my_htoles|||n +my_htonl||| +my_kid||| +my_letoh16|||n +my_letoh32|||n +my_letoh64|||n +my_letohi|||n +my_letohl|||n +my_letohs|||n +my_lstat||| +my_memcmp||5.004000|n +my_memset|||n +my_ntohl||| +my_pclose||5.004000| +my_popen_list||5.007001| +my_popen||5.004000| +my_setenv||| +my_snprintf|5.009004||pvn +my_socketpair||5.007003|n +my_sprintf|5.009003||pvn +my_stat||| +my_strftime||5.007002| +my_strlcat|5.009004||pn +my_strlcpy|5.009004||pn +my_swabn|||n +my_swap||| +my_unexec||| +my_vsnprintf||5.009004|n +need_utf8|||n +newANONATTRSUB||5.006000| +newANONHASH||| +newANONLIST||| +newANONSUB||| +newASSIGNOP||| +newATTRSUB||5.006000| +newAVREF||| +newAV||| +newBINOP||| +newCONDOP||| +newCONSTSUB|5.004050||p +newCVREF||| +newDEFSVOP||| +newFORM||| +newFOROP||| +newGIVENOP||5.009003| +newGIVWHENOP||| +newGP||| +newGVOP||| +newGVREF||| +newGVgen||| +newHVREF||| +newHVhv||5.005000| +newHV||| +newIO||| +newLISTOP||| +newLOGOP||| +newLOOPEX||| +newLOOPOP||| +newMADPROP||| +newMADsv||| +newMYSUB||| +newNULLLIST||| +newOP||| +newPADOP||| +newPMOP||| +newPROG||| +newPVOP||| +newRANGE||| +newRV_inc|5.004000||p +newRV_noinc|5.004000||p +newRV||| +newSLICEOP||| +newSTATEOP||| +newSUB||| +newSVOP||| +newSVREF||| +newSV_type|5.009005||p +newSVhek||5.009003| +newSViv||| +newSVnv||| +newSVpvf_nocontext|||vn +newSVpvf||5.004000|v +newSVpvn_flags|5.011000||p +newSVpvn_share|5.007001||p +newSVpvn_utf8|5.011000||p +newSVpvn|5.004050||p +newSVpvs_flags|5.011000||p +newSVpvs_share||5.009003| +newSVpvs|5.009003||p +newSVpv||| +newSVrv||| +newSVsv||| +newSVuv|5.006000||p +newSV||| +newTOKEN||| +newUNOP||| +newWHENOP||5.009003| +newWHILEOP||5.009003| +newXS_flags||5.009004| +newXSproto||5.006000| +newXS||5.006000| +new_collate||5.006000| +new_constant||| +new_ctype||5.006000| +new_he||| +new_logop||| +new_numeric||5.006000| +new_stackinfo||5.005000| +new_version||5.009000| +new_warnings_bitfield||| +next_symbol||| +nextargv||| +nextchar||| +ninstr||| +no_bareword_allowed||| +no_fh_allowed||| +no_op||| +not_a_number||| +nothreadhook||5.008000| +nuke_stacks||| +num_overflow|||n +offer_nice_chunk||| +oopsAV||| +oopsHV||| +op_clear||| +op_const_sv||| +op_dump||5.006000| +op_free||| +op_getmad_weak||| +op_getmad||| +op_null||5.007002| +op_refcnt_dec||| +op_refcnt_inc||| +op_refcnt_lock||5.009002| +op_refcnt_unlock||5.009002| +op_xmldump||| +open_script||| +pMY_CXT_|5.007003||p +pMY_CXT|5.007003||p +pTHX_|5.006000||p +pTHX|5.006000||p +packWARN|5.007003||p +pack_cat||5.007003| +pack_rec||| +package||| +packlist||5.008001| +pad_add_anon||| +pad_add_name||| +pad_alloc||| +pad_block_start||| +pad_check_dup||| +pad_compname_type||| +pad_findlex||| +pad_findmy||| +pad_fixup_inner_anons||| +pad_free||| +pad_leavemy||| +pad_new||| +pad_peg|||n +pad_push||| +pad_reset||| +pad_setsv||| +pad_sv||5.011000| +pad_swipe||| +pad_tidy||| +pad_undef||| +parse_body||| +parse_unicode_opts||| +parser_dup||| +parser_free||| +path_is_absolute|||n +peep||| +pending_Slabs_to_ro||| +perl_alloc_using|||n +perl_alloc|||n +perl_clone_using|||n +perl_clone|||n +perl_construct|||n +perl_destruct||5.007003|n +perl_free|||n +perl_parse||5.006000|n +perl_run|||n +pidgone||| +pm_description||| +pmflag||| +pmop_dump||5.006000| +pmop_xmldump||| +pmruntime||| +pmtrans||| +pop_scope||| +pregcomp||5.009005| +pregexec||| +pregfree2||5.011000| +pregfree||| +prepend_elem||| +prepend_madprops||| +printbuf||| +printf_nocontext|||vn +process_special_blocks||| +ptr_table_clear||5.009005| +ptr_table_fetch||5.009005| +ptr_table_find|||n +ptr_table_free||5.009005| +ptr_table_new||5.009005| +ptr_table_split||5.009005| +ptr_table_store||5.009005| +push_scope||| +put_byte||| +pv_display|5.006000||p +pv_escape|5.009004||p +pv_pretty|5.009004||p +pv_uni_display||5.007003| +qerror||| +qsortsvu||| +re_compile||5.009005| +re_croak2||| +re_dup_guts||| +re_intuit_start||5.009005| +re_intuit_string||5.006000| +readpipe_override||| +realloc||5.007002|n +reentrant_free||| +reentrant_init||| +reentrant_retry|||vn +reentrant_size||| +ref_array_or_hash||| +refcounted_he_chain_2hv||| +refcounted_he_fetch||| +refcounted_he_free||| +refcounted_he_new_common||| +refcounted_he_new||| +refcounted_he_value||| +refkids||| +refto||| +ref||5.011000| +reg_check_named_buff_matched||| +reg_named_buff_all||5.009005| +reg_named_buff_exists||5.009005| +reg_named_buff_fetch||5.009005| +reg_named_buff_firstkey||5.009005| +reg_named_buff_iter||| +reg_named_buff_nextkey||5.009005| +reg_named_buff_scalar||5.009005| +reg_named_buff||| +reg_namedseq||| +reg_node||| +reg_numbered_buff_fetch||| +reg_numbered_buff_length||| +reg_numbered_buff_store||| +reg_qr_package||| +reg_recode||| +reg_scan_name||| +reg_skipcomment||| +reg_temp_copy||| +reganode||| +regatom||| +regbranch||| +regclass_swash||5.009004| +regclass||| +regcppop||| +regcppush||| +regcurly|||n +regdump_extflags||| +regdump||5.005000| +regdupe_internal||| +regexec_flags||5.005000| +regfree_internal||5.009005| +reghop3|||n +reghop4|||n +reghopmaybe3|||n +reginclass||| +reginitcolors||5.006000| +reginsert||| +regmatch||| +regnext||5.005000| +regpiece||| +regpposixcc||| +regprop||| +regrepeat||| +regtail_study||| +regtail||| +regtry||| +reguni||| +regwhite|||n +reg||| +repeatcpy||| +report_evil_fh||| +report_uninit||| +require_pv||5.006000| +require_tie_mod||| +restore_magic||| +rninstr||| +rsignal_restore||| +rsignal_save||| +rsignal_state||5.004000| +rsignal||5.004000| +run_body||| +run_user_filter||| +runops_debug||5.005000| +runops_standard||5.005000| +rvpv_dup||| +rxres_free||| +rxres_restore||| +rxres_save||| +safesyscalloc||5.006000|n +safesysfree||5.006000|n +safesysmalloc||5.006000|n +safesysrealloc||5.006000|n +same_dirent||| +save_I16||5.004000| +save_I32||| +save_I8||5.006000| +save_adelete||5.011000| +save_aelem||5.004050| +save_alloc||5.006000| +save_aptr||| +save_ary||| +save_bool||5.008001| +save_clearsv||| +save_delete||| +save_destructor_x||5.006000| +save_destructor||5.006000| +save_freeop||| +save_freepv||| +save_freesv||| +save_generic_pvref||5.006001| +save_generic_svref||5.005030| +save_gp||5.004000| +save_hash||| +save_hek_flags|||n +save_helem_flags||5.011000| +save_helem||5.004050| +save_hints||| +save_hptr||| +save_int||| +save_item||| +save_iv||5.005000| +save_lines||| +save_list||| +save_long||| +save_magic||| +save_mortalizesv||5.007001| +save_nogv||| +save_op||| +save_padsv_and_mortalize||5.011000| +save_pptr||| +save_pushi32ptr||| +save_pushptri32ptr||| +save_pushptrptr||| +save_pushptr||5.011000| +save_re_context||5.006000| +save_scalar_at||| +save_scalar||| +save_set_svflags||5.009000| +save_shared_pvref||5.007003| +save_sptr||| +save_svref||| +save_vptr||5.006000| +savepvn||| +savepvs||5.009003| +savepv||| +savesharedpvn||5.009005| +savesharedpv||5.007003| +savestack_grow_cnt||5.008001| +savestack_grow||| +savesvpv||5.009002| +sawparens||| +scalar_mod_type|||n +scalarboolean||| +scalarkids||| +scalarseq||| +scalarvoid||| +scalar||| +scan_bin||5.006000| +scan_commit||| +scan_const||| +scan_formline||| +scan_heredoc||| +scan_hex||| +scan_ident||| +scan_inputsymbol||| +scan_num||5.007001| +scan_oct||| +scan_pat||| +scan_str||| +scan_subst||| +scan_trans||| +scan_version||5.009001| +scan_vstring||5.009005| +scan_word||| +scope||| +screaminstr||5.005000| +search_const||| +seed||5.008001| +sequence_num||| +sequence_tail||| +sequence||| +set_context||5.006000|n +set_numeric_local||5.006000| +set_numeric_radix||5.006000| +set_numeric_standard||5.006000| +setdefout||| +share_hek_flags||| +share_hek||5.004000| +si_dup||| +sighandler|||n +simplify_sort||| +skipspace0||| +skipspace1||| +skipspace2||| +skipspace||| +softref2xv||| +sortcv_stacked||| +sortcv_xsub||| +sortcv||| +sortsv_flags||5.009003| +sortsv||5.007003| +space_join_names_mortal||| +ss_dup||| +stack_grow||| +start_force||| +start_glob||| +start_subparse||5.004000| +stashpv_hvname_match||5.011000| +stdize_locale||| +store_cop_label||| +strEQ||| +strGE||| +strGT||| +strLE||| +strLT||| +strNE||| +str_to_version||5.006000| +strip_return||| +strnEQ||| +strnNE||| +study_chunk||| +sub_crush_depth||| +sublex_done||| +sublex_push||| +sublex_start||| +sv_2bool||| +sv_2cv||| +sv_2io||| +sv_2iuv_common||| +sv_2iuv_non_preserve||| +sv_2iv_flags||5.009001| +sv_2iv||| +sv_2mortal||| +sv_2num||| +sv_2nv||| +sv_2pv_flags|5.007002||p +sv_2pv_nolen|5.006000||p +sv_2pvbyte_nolen|5.006000||p +sv_2pvbyte|5.006000||p +sv_2pvutf8_nolen||5.006000| +sv_2pvutf8||5.006000| +sv_2pv||| +sv_2uv_flags||5.009001| +sv_2uv|5.004000||p +sv_add_arena||| +sv_add_backref||| +sv_backoff||| +sv_bless||| +sv_cat_decode||5.008001| +sv_catpv_mg|5.004050||p +sv_catpvf_mg_nocontext|||pvn +sv_catpvf_mg|5.006000|5.004000|pv +sv_catpvf_nocontext|||vn +sv_catpvf||5.004000|v +sv_catpvn_flags||5.007002| +sv_catpvn_mg|5.004050||p +sv_catpvn_nomg|5.007002||p +sv_catpvn||| +sv_catpvs|5.009003||p +sv_catpv||| +sv_catsv_flags||5.007002| +sv_catsv_mg|5.004050||p +sv_catsv_nomg|5.007002||p +sv_catsv||| +sv_catxmlpvn||| +sv_catxmlsv||| +sv_chop||| +sv_clean_all||| +sv_clean_objs||| +sv_clear||| +sv_cmp_locale||5.004000| +sv_cmp||| +sv_collxfrm||| +sv_compile_2op||5.008001| +sv_copypv||5.007003| +sv_dec||| +sv_del_backref||| +sv_derived_from||5.004000| +sv_destroyable||5.010000| +sv_does||5.009004| +sv_dump||| +sv_dup_inc_multiple||| +sv_dup||| +sv_eq||| +sv_exp_grow||| +sv_force_normal_flags||5.007001| +sv_force_normal||5.006000| +sv_free2||| +sv_free_arenas||| +sv_free||| +sv_gets||5.004000| +sv_grow||| +sv_i_ncmp||| +sv_inc||| +sv_insert_flags||5.011000| +sv_insert||| +sv_isa||| +sv_isobject||| +sv_iv||5.005000| +sv_kill_backrefs||| +sv_len_utf8||5.006000| +sv_len||| +sv_magic_portable|5.011000|5.004000|p +sv_magicext||5.007003| +sv_magic||| +sv_mortalcopy||| +sv_ncmp||| +sv_newmortal||| +sv_newref||| +sv_nolocking||5.007003| +sv_nosharing||5.007003| +sv_nounlocking||| +sv_nv||5.005000| +sv_peek||5.005000| +sv_pos_b2u_midway||| +sv_pos_b2u||5.006000| +sv_pos_u2b_cached||| +sv_pos_u2b_forwards|||n +sv_pos_u2b_midway|||n +sv_pos_u2b||5.006000| +sv_pvbyten_force||5.006000| +sv_pvbyten||5.006000| +sv_pvbyte||5.006000| +sv_pvn_force_flags|5.007002||p +sv_pvn_force||| +sv_pvn_nomg|5.007003|5.005000|p +sv_pvn||5.005000| +sv_pvutf8n_force||5.006000| +sv_pvutf8n||5.006000| +sv_pvutf8||5.006000| +sv_pv||5.006000| +sv_recode_to_utf8||5.007003| +sv_reftype||| +sv_release_COW||| +sv_replace||| +sv_report_used||| +sv_reset||| +sv_rvweaken||5.006000| +sv_setiv_mg|5.004050||p +sv_setiv||| +sv_setnv_mg|5.006000||p +sv_setnv||| +sv_setpv_mg|5.004050||p +sv_setpvf_mg_nocontext|||pvn +sv_setpvf_mg|5.006000|5.004000|pv +sv_setpvf_nocontext|||vn +sv_setpvf||5.004000|v +sv_setpviv_mg||5.008001| +sv_setpviv||5.008001| +sv_setpvn_mg|5.004050||p +sv_setpvn||| +sv_setpvs|5.009004||p +sv_setpv||| +sv_setref_iv||| +sv_setref_nv||| +sv_setref_pvn||| +sv_setref_pv||| +sv_setref_uv||5.007001| +sv_setsv_cow||| +sv_setsv_flags||5.007002| +sv_setsv_mg|5.004050||p +sv_setsv_nomg|5.007002||p +sv_setsv||| +sv_setuv_mg|5.004050||p +sv_setuv|5.004000||p +sv_tainted||5.004000| +sv_taint||5.004000| +sv_true||5.005000| +sv_unglob||| +sv_uni_display||5.007003| +sv_unmagic||| +sv_unref_flags||5.007001| +sv_unref||| +sv_untaint||5.004000| +sv_upgrade||| +sv_usepvn_flags||5.009004| +sv_usepvn_mg|5.004050||p +sv_usepvn||| +sv_utf8_decode||5.006000| +sv_utf8_downgrade||5.006000| +sv_utf8_encode||5.006000| +sv_utf8_upgrade_flags_grow||5.011000| +sv_utf8_upgrade_flags||5.007002| +sv_utf8_upgrade_nomg||5.007002| +sv_utf8_upgrade||5.007001| +sv_uv|5.005000||p +sv_vcatpvf_mg|5.006000|5.004000|p +sv_vcatpvfn||5.004000| +sv_vcatpvf|5.006000|5.004000|p +sv_vsetpvf_mg|5.006000|5.004000|p +sv_vsetpvfn||5.004000| +sv_vsetpvf|5.006000|5.004000|p +sv_xmlpeek||| +svtype||| +swallow_bom||| +swap_match_buff||| +swash_fetch||5.007002| +swash_get||| +swash_init||5.006000| +sys_init3||5.010000|n +sys_init||5.010000|n +sys_intern_clear||| +sys_intern_dup||| +sys_intern_init||| +sys_term||5.010000|n +taint_env||| +taint_proper||| +tmps_grow||5.006000| +toLOWER||| +toUPPER||| +to_byte_substr||| +to_uni_fold||5.007003| +to_uni_lower_lc||5.006000| +to_uni_lower||5.007003| +to_uni_title_lc||5.006000| +to_uni_title||5.007003| +to_uni_upper_lc||5.006000| +to_uni_upper||5.007003| +to_utf8_case||5.007003| +to_utf8_fold||5.007003| +to_utf8_lower||5.007003| +to_utf8_substr||| +to_utf8_title||5.007003| +to_utf8_upper||5.007003| +token_free||| +token_getmad||| +tokenize_use||| +tokeq||| +tokereport||| +too_few_arguments||| +too_many_arguments||| +uiv_2buf|||n +unlnk||| +unpack_rec||| +unpack_str||5.007003| +unpackstring||5.008001| +unshare_hek_or_pvn||| +unshare_hek||| +unsharepvn||5.004000| +unwind_handler_stack||| +update_debugger_info||| +upg_version||5.009005| +usage||| +utf16_to_utf8_reversed||5.006001| +utf16_to_utf8||5.006001| +utf8_distance||5.006000| +utf8_hop||5.006000| +utf8_length||5.007001| +utf8_mg_pos_cache_update||| +utf8_to_bytes||5.006001| +utf8_to_uvchr||5.007001| +utf8_to_uvuni||5.007001| +utf8n_to_uvchr||| +utf8n_to_uvuni||5.007001| +utilize||| +uvchr_to_utf8_flags||5.007003| +uvchr_to_utf8||| +uvuni_to_utf8_flags||5.007003| +uvuni_to_utf8||5.007001| +validate_suid||| +varname||| +vcmp||5.009000| +vcroak||5.006000| +vdeb||5.007003| +vdie_common||| +vdie_croak_common||| +vdie||| +vform||5.006000| +visit||| +vivify_defelem||| +vivify_ref||| +vload_module|5.006000||p +vmess||5.006000| +vnewSVpvf|5.006000|5.004000|p +vnormal||5.009002| +vnumify||5.009000| +vstringify||5.009000| +vverify||5.009003| +vwarner||5.006000| +vwarn||5.006000| +wait4pid||| +warn_nocontext|||vn +warner_nocontext|||vn +warner|5.006000|5.004000|pv +warn|||v +watch||| +whichsig||| +write_no_mem||| +write_to_stderr||| +xmldump_all||| +xmldump_attr||| +xmldump_eval||| +xmldump_form||| +xmldump_indent|||v +xmldump_packsubs||| +xmldump_sub||| +xmldump_vindent||| +yyerror||| +yylex||| +yyparse||| +yywarn||| +); + +if (exists $opt{'list-unsupported'}) { + my $f; + for $f (sort { lc $a cmp lc $b } keys %API) { + next unless $API{$f}{todo}; + print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n"; + } + exit 0; +} + +# Scan for possible replacement candidates + +my(%replace, %need, %hints, %warnings, %depends); +my $replace = 0; +my($hint, $define, $function); + +sub find_api +{ + my $code = shift; + $code =~ s{ + / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*) + | "[^"\\]*(?:\\.[^"\\]*)*" + | '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx; + grep { exists $API{$_} } $code =~ /(\w+)/mg; +} + +while () { + if ($hint) { + my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings; + if (m{^\s*\*\s(.*?)\s*$}) { + for (@{$hint->[1]}) { + $h->{$_} ||= ''; # suppress warning with older perls + $h->{$_} .= "$1\n"; + } + } + else { undef $hint } + } + + $hint = [$1, [split /,?\s+/, $2]] + if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$}; + + if ($define) { + if ($define->[1] =~ /\\$/) { + $define->[1] .= $_; + } + else { + if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) { + my @n = find_api($define->[1]); + push @{$depends{$define->[0]}}, @n if @n + } + undef $define; + } + } + + $define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)}; + + if ($function) { + if (/^}/) { + if (exists $API{$function->[0]}) { + my @n = find_api($function->[1]); + push @{$depends{$function->[0]}}, @n if @n + } + undef $function; + } + else { + $function->[1] .= $_; + } + } + + $function = [$1, ''] if m{^DPPP_\(my_(\w+)\)}; + + $replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$}; + $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)}; + $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce}; + $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$}; + + if (m{^\s*$rccs\s+(\w+(\s*,\s*\w+)*)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) { + my @deps = map { s/\s+//g; $_ } split /,/, $3; + my $d; + for $d (map { s/\s+//g; $_ } split /,/, $1) { + push @{$depends{$d}}, @deps; + } + } + + $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)}; +} + +for (values %depends) { + my %s; + $_ = [sort grep !$s{$_}++, @$_]; +} + +if (exists $opt{'api-info'}) { + my $f; + my $count = 0; + my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$"; + for $f (sort { lc $a cmp lc $b } keys %API) { + next unless $f =~ /$match/; + print "\n=== $f ===\n\n"; + my $info = 0; + if ($API{$f}{base} || $API{$f}{todo}) { + my $base = format_version($API{$f}{base} || $API{$f}{todo}); + print "Supported at least starting from perl-$base.\n"; + $info++; + } + if ($API{$f}{provided}) { + my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003"; + print "Support by $ppport provided back to perl-$todo.\n"; + print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f}; + print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f}; + print "\n$hints{$f}" if exists $hints{$f}; + print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f}; + $info++; + } + print "No portability information available.\n" unless $info; + $count++; + } + $count or print "Found no API matching '$opt{'api-info'}'."; + print "\n"; + exit 0; +} + +if (exists $opt{'list-provided'}) { + my $f; + for $f (sort { lc $a cmp lc $b } keys %API) { + next unless $API{$f}{provided}; + my @flags; + push @flags, 'explicit' if exists $need{$f}; + push @flags, 'depend' if exists $depends{$f}; + push @flags, 'hint' if exists $hints{$f}; + push @flags, 'warning' if exists $warnings{$f}; + my $flags = @flags ? ' ['.join(', ', @flags).']' : ''; + print "$f$flags\n"; + } + exit 0; +} + +my @files; +my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc ); +my $srcext = join '|', map { quotemeta $_ } @srcext; + +if (@ARGV) { + my %seen; + for (@ARGV) { + if (-e) { + if (-f) { + push @files, $_ unless $seen{$_}++; + } + else { warn "'$_' is not a file.\n" } + } + else { + my @new = grep { -f } glob $_ + or warn "'$_' does not exist.\n"; + push @files, grep { !$seen{$_}++ } @new; + } + } +} +else { + eval { + require File::Find; + File::Find::find(sub { + $File::Find::name =~ /($srcext)$/i + and push @files, $File::Find::name; + }, '.'); + }; + if ($@) { + @files = map { glob "*$_" } @srcext; + } +} + +if (!@ARGV || $opt{filter}) { + my(@in, @out); + my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files; + for (@files) { + my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i; + push @{ $out ? \@out : \@in }, $_; + } + if (@ARGV && @out) { + warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out); + } + @files = @in; +} + +die "No input files given!\n" unless @files; + +my(%files, %global, %revreplace); +%revreplace = reverse %replace; +my $filename; +my $patch_opened = 0; + +for $filename (@files) { + unless (open IN, "<$filename") { + warn "Unable to read from $filename: $!\n"; + next; + } + + info("Scanning $filename ..."); + + my $c = do { local $/; }; + close IN; + + my %file = (orig => $c, changes => 0); + + # Temporarily remove C/XS comments and strings from the code + my @ccom; + + $c =~ s{ + ( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]* + | ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* ) + | ( ^$HS*\#[^\r\n]* + | "[^"\\]*(?:\\.[^"\\]*)*" + | '[^'\\]*(?:\\.[^'\\]*)*' + | / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) ) + }{ defined $2 and push @ccom, $2; + defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex; + + $file{ccom} = \@ccom; + $file{code} = $c; + $file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m; + + my $func; + + for $func (keys %API) { + my $match = $func; + $match .= "|$revreplace{$func}" if exists $revreplace{$func}; + if ($c =~ /\b(?:Perl_)?($match)\b/) { + $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func}; + $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/; + if (exists $API{$func}{provided}) { + $file{uses_provided}{$func}++; + if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) { + $file{uses}{$func}++; + my @deps = rec_depend($func); + if (@deps) { + $file{uses_deps}{$func} = \@deps; + for (@deps) { + $file{uses}{$_} = 0 unless exists $file{uses}{$_}; + } + } + for ($func, @deps) { + $file{needs}{$_} = 'static' if exists $need{$_}; + } + } + } + if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) { + if ($c =~ /\b$func\b/) { + $file{uses_todo}{$func}++; + } + } + } + } + + while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) { + if (exists $need{$2}) { + $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++; + } + else { warning("Possibly wrong #define $1 in $filename") } + } + + for (qw(uses needs uses_todo needed_global needed_static)) { + for $func (keys %{$file{$_}}) { + push @{$global{$_}{$func}}, $filename; + } + } + + $files{$filename} = \%file; +} + +# Globally resolve NEED_'s +my $need; +for $need (keys %{$global{needs}}) { + if (@{$global{needs}{$need}} > 1) { + my @targets = @{$global{needs}{$need}}; + my @t = grep $files{$_}{needed_global}{$need}, @targets; + @targets = @t if @t; + @t = grep /\.xs$/i, @targets; + @targets = @t if @t; + my $target = shift @targets; + $files{$target}{needs}{$need} = 'global'; + for (@{$global{needs}{$need}}) { + $files{$_}{needs}{$need} = 'extern' if $_ ne $target; + } + } +} + +for $filename (@files) { + exists $files{$filename} or next; + + info("=== Analyzing $filename ==="); + + my %file = %{$files{$filename}}; + my $func; + my $c = $file{code}; + my $warnings = 0; + + for $func (sort keys %{$file{uses_Perl}}) { + if ($API{$func}{varargs}) { + unless ($API{$func}{nothxarg}) { + my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))} + { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge); + if ($changes) { + warning("Doesn't pass interpreter argument aTHX to Perl_$func"); + $file{changes} += $changes; + } + } + } + else { + warning("Uses Perl_$func instead of $func"); + $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*} + {$func$1(}g); + } + } + + for $func (sort keys %{$file{uses_replace}}) { + warning("Uses $func instead of $replace{$func}"); + $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g); + } + + for $func (sort keys %{$file{uses_provided}}) { + if ($file{uses}{$func}) { + if (exists $file{uses_deps}{$func}) { + diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}})); + } + else { + diag("Uses $func"); + } + } + $warnings += hint($func); + } + + unless ($opt{quiet}) { + for $func (sort keys %{$file{uses_todo}}) { + print "*** WARNING: Uses $func, which may not be portable below perl ", + format_version($API{$func}{todo}), ", even with '$ppport'\n"; + $warnings++; + } + } + + for $func (sort keys %{$file{needed_static}}) { + my $message = ''; + if (not exists $file{uses}{$func}) { + $message = "No need to define NEED_$func if $func is never used"; + } + elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') { + $message = "No need to define NEED_$func when already needed globally"; + } + if ($message) { + diag($message); + $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg); + } + } + + for $func (sort keys %{$file{needed_global}}) { + my $message = ''; + if (not exists $global{uses}{$func}) { + $message = "No need to define NEED_${func}_GLOBAL if $func is never used"; + } + elsif (exists $file{needs}{$func}) { + if ($file{needs}{$func} eq 'extern') { + $message = "No need to define NEED_${func}_GLOBAL when already needed globally"; + } + elsif ($file{needs}{$func} eq 'static') { + $message = "No need to define NEED_${func}_GLOBAL when only used in this file"; + } + } + if ($message) { + diag($message); + $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg); + } + } + + $file{needs_inc_ppport} = keys %{$file{uses}}; + + if ($file{needs_inc_ppport}) { + my $pp = ''; + + for $func (sort keys %{$file{needs}}) { + my $type = $file{needs}{$func}; + next if $type eq 'extern'; + my $suffix = $type eq 'global' ? '_GLOBAL' : ''; + unless (exists $file{"needed_$type"}{$func}) { + if ($type eq 'global') { + diag("Files [@{$global{needs}{$func}}] need $func, adding global request"); + } + else { + diag("File needs $func, adding static request"); + } + $pp .= "#define NEED_$func$suffix\n"; + } + } + + if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) { + $pp = ''; + $file{changes}++; + } + + unless ($file{has_inc_ppport}) { + diag("Needs to include '$ppport'"); + $pp .= qq(#include "$ppport"\n) + } + + if ($pp) { + $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms) + || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m) + || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m) + || ($c =~ s/^/$pp/); + } + } + else { + if ($file{has_inc_ppport}) { + diag("No need to include '$ppport'"); + $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m); + } + } + + # put back in our C comments + my $ix; + my $cppc = 0; + my @ccom = @{$file{ccom}}; + for $ix (0 .. $#ccom) { + if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) { + $cppc++; + $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/; + } + else { + $c =~ s/$rccs$ix$rcce/$ccom[$ix]/; + } + } + + if ($cppc) { + my $s = $cppc != 1 ? 's' : ''; + warning("Uses $cppc C++ style comment$s, which is not portable"); + } + + my $s = $warnings != 1 ? 's' : ''; + my $warn = $warnings ? " ($warnings warning$s)" : ''; + info("Analysis completed$warn"); + + if ($file{changes}) { + if (exists $opt{copy}) { + my $newfile = "$filename$opt{copy}"; + if (-e $newfile) { + error("'$newfile' already exists, refusing to write copy of '$filename'"); + } + else { + local *F; + if (open F, ">$newfile") { + info("Writing copy of '$filename' with changes to '$newfile'"); + print F $c; + close F; + } + else { + error("Cannot open '$newfile' for writing: $!"); + } + } + } + elsif (exists $opt{patch} || $opt{changes}) { + if (exists $opt{patch}) { + unless ($patch_opened) { + if (open PATCH, ">$opt{patch}") { + $patch_opened = 1; + } + else { + error("Cannot open '$opt{patch}' for writing: $!"); + delete $opt{patch}; + $opt{changes} = 1; + goto fallback; + } + } + mydiff(\*PATCH, $filename, $c); + } + else { +fallback: + info("Suggested changes:"); + mydiff(\*STDOUT, $filename, $c); + } + } + else { + my $s = $file{changes} == 1 ? '' : 's'; + info("$file{changes} potentially required change$s detected"); + } + } + else { + info("Looks good"); + } +} + +close PATCH if $patch_opened; + +exit 0; + + +sub try_use { eval "use @_;"; return $@ eq '' } + +sub mydiff +{ + local *F = shift; + my($file, $str) = @_; + my $diff; + + if (exists $opt{diff}) { + $diff = run_diff($opt{diff}, $file, $str); + } + + if (!defined $diff and try_use('Text::Diff')) { + $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' }); + $diff = <
$tmp") { + print F $str; + close F; + + if (open F, "$prog $file $tmp |") { + while () { + s/\Q$tmp\E/$file.patched/; + $diff .= $_; + } + close F; + unlink $tmp; + return $diff; + } + + unlink $tmp; + } + else { + error("Cannot open '$tmp' for writing: $!"); + } + + return undef; +} + +sub rec_depend +{ + my($func, $seen) = @_; + return () unless exists $depends{$func}; + $seen = {%{$seen||{}}}; + return () if $seen->{$func}++; + my %s; + grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}}; +} + +sub parse_version +{ + my $ver = shift; + + if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) { + return ($1, $2, $3); + } + elsif ($ver !~ /^\d+\.[\d_]+$/) { + die "cannot parse version '$ver'\n"; + } + + $ver =~ s/_//g; + $ver =~ s/$/000000/; + + my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; + + $v = int $v; + $s = int $s; + + if ($r < 5 || ($r == 5 && $v < 6)) { + if ($s % 10) { + die "cannot parse version '$ver'\n"; + } + } + + return ($r, $v, $s); +} + +sub format_version +{ + my $ver = shift; + + $ver =~ s/$/000000/; + my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; + + $v = int $v; + $s = int $s; + + if ($r < 5 || ($r == 5 && $v < 6)) { + if ($s % 10) { + die "invalid version '$ver'\n"; + } + $s /= 10; + + $ver = sprintf "%d.%03d", $r, $v; + $s > 0 and $ver .= sprintf "_%02d", $s; + + return $ver; + } + + return sprintf "%d.%d.%d", $r, $v, $s; +} + +sub info +{ + $opt{quiet} and return; + print @_, "\n"; +} + +sub diag +{ + $opt{quiet} and return; + $opt{diag} and print @_, "\n"; +} + +sub warning +{ + $opt{quiet} and return; + print "*** ", @_, "\n"; +} + +sub error +{ + print "*** ERROR: ", @_, "\n"; +} + +my %given_hints; +my %given_warnings; +sub hint +{ + $opt{quiet} and return; + my $func = shift; + my $rv = 0; + if (exists $warnings{$func} && !$given_warnings{$func}++) { + my $warn = $warnings{$func}; + $warn =~ s!^!*** !mg; + print "*** WARNING: $func\n", $warn; + $rv++; + } + if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) { + my $hint = $hints{$func}; + $hint =~ s/^/ /mg; + print " --- hint for $func ---\n", $hint; + } + $rv; +} + +sub usage +{ + my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms; + my %M = ( 'I' => '*' ); + $usage =~ s/^\s*perl\s+\S+/$^X $0/; + $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g; + + print < }; + my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms; + $copy =~ s/^(?=\S+)/ /gms; + $self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms; + $self =~ s/^SKIP.*(?=^__DATA__)/SKIP +if (\@ARGV && \$ARGV[0] eq '--unstrip') { + eval { require Devel::PPPort }; + \$@ and die "Cannot require Devel::PPPort, please install.\\n"; + if (eval \$Devel::PPPort::VERSION < $VERSION) { + die "$0 was originally generated with Devel::PPPort $VERSION.\\n" + . "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n" + . "Please install a newer version, or --unstrip will not work.\\n"; + } + Devel::PPPort::WriteFile(\$0); + exit 0; +} +print <$0" or die "cannot strip $0: $!\n"; + print OUT "$pl$c\n"; + + exit 0; +} + +__DATA__ +*/ + +#ifndef _P_P_PORTABILITY_H_ +#define _P_P_PORTABILITY_H_ + +#ifndef DPPP_NAMESPACE +# define DPPP_NAMESPACE DPPP_ +#endif + +#define DPPP_CAT2(x,y) CAT2(x,y) +#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name) + +#ifndef PERL_REVISION +# if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION)) +# define PERL_PATCHLEVEL_H_IMPLICIT +# include +# endif +# if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL))) +# include +# endif +# ifndef PERL_REVISION +# define PERL_REVISION (5) + /* Replace: 1 */ +# define PERL_VERSION PATCHLEVEL +# define PERL_SUBVERSION SUBVERSION + /* Replace PERL_PATCHLEVEL with PERL_VERSION */ + /* Replace: 0 */ +# endif +#endif + +#define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10)) +#define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION)) + +/* It is very unlikely that anyone will try to use this with Perl 6 + (or greater), but who knows. + */ +#if PERL_REVISION != 5 +# error ppport.h only works with Perl version 5 +#endif /* PERL_REVISION != 5 */ +#ifndef dTHR +# define dTHR dNOOP +#endif +#ifndef dTHX +# define dTHX dNOOP +#endif + +#ifndef dTHXa +# define dTHXa(x) dNOOP +#endif +#ifndef pTHX +# define pTHX void +#endif + +#ifndef pTHX_ +# define pTHX_ +#endif + +#ifndef aTHX +# define aTHX +#endif + +#ifndef aTHX_ +# define aTHX_ +#endif + +#if (PERL_BCDVERSION < 0x5006000) +# ifdef USE_THREADS +# define aTHXR thr +# define aTHXR_ thr, +# else +# define aTHXR +# define aTHXR_ +# endif +# define dTHXR dTHR +#else +# define aTHXR aTHX +# define aTHXR_ aTHX_ +# define dTHXR dTHX +#endif +#ifndef dTHXoa +# define dTHXoa(x) dTHXa(x) +#endif + +#ifdef I_LIMITS +# include +#endif + +#ifndef PERL_UCHAR_MIN +# define PERL_UCHAR_MIN ((unsigned char)0) +#endif + +#ifndef PERL_UCHAR_MAX +# ifdef UCHAR_MAX +# define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX) +# else +# ifdef MAXUCHAR +# define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR) +# else +# define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0) +# endif +# endif +#endif + +#ifndef PERL_USHORT_MIN +# define PERL_USHORT_MIN ((unsigned short)0) +#endif + +#ifndef PERL_USHORT_MAX +# ifdef USHORT_MAX +# define PERL_USHORT_MAX ((unsigned short)USHORT_MAX) +# else +# ifdef MAXUSHORT +# define PERL_USHORT_MAX ((unsigned short)MAXUSHORT) +# else +# ifdef USHRT_MAX +# define PERL_USHORT_MAX ((unsigned short)USHRT_MAX) +# else +# define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) +# endif +# endif +# endif +#endif + +#ifndef PERL_SHORT_MAX +# ifdef SHORT_MAX +# define PERL_SHORT_MAX ((short)SHORT_MAX) +# else +# ifdef MAXSHORT /* Often used in */ +# define PERL_SHORT_MAX ((short)MAXSHORT) +# else +# ifdef SHRT_MAX +# define PERL_SHORT_MAX ((short)SHRT_MAX) +# else +# define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1)) +# endif +# endif +# endif +#endif + +#ifndef PERL_SHORT_MIN +# ifdef SHORT_MIN +# define PERL_SHORT_MIN ((short)SHORT_MIN) +# else +# ifdef MINSHORT +# define PERL_SHORT_MIN ((short)MINSHORT) +# else +# ifdef SHRT_MIN +# define PERL_SHORT_MIN ((short)SHRT_MIN) +# else +# define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3)) +# endif +# endif +# endif +#endif + +#ifndef PERL_UINT_MAX +# ifdef UINT_MAX +# define PERL_UINT_MAX ((unsigned int)UINT_MAX) +# else +# ifdef MAXUINT +# define PERL_UINT_MAX ((unsigned int)MAXUINT) +# else +# define PERL_UINT_MAX (~(unsigned int)0) +# endif +# endif +#endif + +#ifndef PERL_UINT_MIN +# define PERL_UINT_MIN ((unsigned int)0) +#endif + +#ifndef PERL_INT_MAX +# ifdef INT_MAX +# define PERL_INT_MAX ((int)INT_MAX) +# else +# ifdef MAXINT /* Often used in */ +# define PERL_INT_MAX ((int)MAXINT) +# else +# define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1)) +# endif +# endif +#endif + +#ifndef PERL_INT_MIN +# ifdef INT_MIN +# define PERL_INT_MIN ((int)INT_MIN) +# else +# ifdef MININT +# define PERL_INT_MIN ((int)MININT) +# else +# define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3)) +# endif +# endif +#endif + +#ifndef PERL_ULONG_MAX +# ifdef ULONG_MAX +# define PERL_ULONG_MAX ((unsigned long)ULONG_MAX) +# else +# ifdef MAXULONG +# define PERL_ULONG_MAX ((unsigned long)MAXULONG) +# else +# define PERL_ULONG_MAX (~(unsigned long)0) +# endif +# endif +#endif + +#ifndef PERL_ULONG_MIN +# define PERL_ULONG_MIN ((unsigned long)0L) +#endif + +#ifndef PERL_LONG_MAX +# ifdef LONG_MAX +# define PERL_LONG_MAX ((long)LONG_MAX) +# else +# ifdef MAXLONG +# define PERL_LONG_MAX ((long)MAXLONG) +# else +# define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1)) +# endif +# endif +#endif + +#ifndef PERL_LONG_MIN +# ifdef LONG_MIN +# define PERL_LONG_MIN ((long)LONG_MIN) +# else +# ifdef MINLONG +# define PERL_LONG_MIN ((long)MINLONG) +# else +# define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3)) +# endif +# endif +#endif + +#if defined(HAS_QUAD) && (defined(convex) || defined(uts)) +# ifndef PERL_UQUAD_MAX +# ifdef ULONGLONG_MAX +# define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX) +# else +# ifdef MAXULONGLONG +# define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG) +# else +# define PERL_UQUAD_MAX (~(unsigned long long)0) +# endif +# endif +# endif + +# ifndef PERL_UQUAD_MIN +# define PERL_UQUAD_MIN ((unsigned long long)0L) +# endif + +# ifndef PERL_QUAD_MAX +# ifdef LONGLONG_MAX +# define PERL_QUAD_MAX ((long long)LONGLONG_MAX) +# else +# ifdef MAXLONGLONG +# define PERL_QUAD_MAX ((long long)MAXLONGLONG) +# else +# define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1)) +# endif +# endif +# endif + +# ifndef PERL_QUAD_MIN +# ifdef LONGLONG_MIN +# define PERL_QUAD_MIN ((long long)LONGLONG_MIN) +# else +# ifdef MINLONGLONG +# define PERL_QUAD_MIN ((long long)MINLONGLONG) +# else +# define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3)) +# endif +# endif +# endif +#endif + +/* This is based on code from 5.003 perl.h */ +#ifdef HAS_QUAD +# ifdef cray +#ifndef IVTYPE +# define IVTYPE int +#endif + +#ifndef IV_MIN +# define IV_MIN PERL_INT_MIN +#endif + +#ifndef IV_MAX +# define IV_MAX PERL_INT_MAX +#endif + +#ifndef UV_MIN +# define UV_MIN PERL_UINT_MIN +#endif + +#ifndef UV_MAX +# define UV_MAX PERL_UINT_MAX +#endif + +# ifdef INTSIZE +#ifndef IVSIZE +# define IVSIZE INTSIZE +#endif + +# endif +# else +# if defined(convex) || defined(uts) +#ifndef IVTYPE +# define IVTYPE long long +#endif + +#ifndef IV_MIN +# define IV_MIN PERL_QUAD_MIN +#endif + +#ifndef IV_MAX +# define IV_MAX PERL_QUAD_MAX +#endif + +#ifndef UV_MIN +# define UV_MIN PERL_UQUAD_MIN +#endif + +#ifndef UV_MAX +# define UV_MAX PERL_UQUAD_MAX +#endif + +# ifdef LONGLONGSIZE +#ifndef IVSIZE +# define IVSIZE LONGLONGSIZE +#endif + +# endif +# else +#ifndef IVTYPE +# define IVTYPE long +#endif + +#ifndef IV_MIN +# define IV_MIN PERL_LONG_MIN +#endif + +#ifndef IV_MAX +# define IV_MAX PERL_LONG_MAX +#endif + +#ifndef UV_MIN +# define UV_MIN PERL_ULONG_MIN +#endif + +#ifndef UV_MAX +# define UV_MAX PERL_ULONG_MAX +#endif + +# ifdef LONGSIZE +#ifndef IVSIZE +# define IVSIZE LONGSIZE +#endif + +# endif +# endif +# endif +#ifndef IVSIZE +# define IVSIZE 8 +#endif + +#ifndef PERL_QUAD_MIN +# define PERL_QUAD_MIN IV_MIN +#endif + +#ifndef PERL_QUAD_MAX +# define PERL_QUAD_MAX IV_MAX +#endif + +#ifndef PERL_UQUAD_MIN +# define PERL_UQUAD_MIN UV_MIN +#endif + +#ifndef PERL_UQUAD_MAX +# define PERL_UQUAD_MAX UV_MAX +#endif + +#else +#ifndef IVTYPE +# define IVTYPE long +#endif + +#ifndef IV_MIN +# define IV_MIN PERL_LONG_MIN +#endif + +#ifndef IV_MAX +# define IV_MAX PERL_LONG_MAX +#endif + +#ifndef UV_MIN +# define UV_MIN PERL_ULONG_MIN +#endif + +#ifndef UV_MAX +# define UV_MAX PERL_ULONG_MAX +#endif + +#endif + +#ifndef IVSIZE +# ifdef LONGSIZE +# define IVSIZE LONGSIZE +# else +# define IVSIZE 4 /* A bold guess, but the best we can make. */ +# endif +#endif +#ifndef UVTYPE +# define UVTYPE unsigned IVTYPE +#endif + +#ifndef UVSIZE +# define UVSIZE IVSIZE +#endif +#ifndef sv_setuv +# define sv_setuv(sv, uv) \ + STMT_START { \ + UV TeMpUv = uv; \ + if (TeMpUv <= IV_MAX) \ + sv_setiv(sv, TeMpUv); \ + else \ + sv_setnv(sv, (double)TeMpUv); \ + } STMT_END +#endif +#ifndef newSVuv +# define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv)) +#endif +#ifndef sv_2uv +# define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv))) +#endif + +#ifndef SvUVX +# define SvUVX(sv) ((UV)SvIVX(sv)) +#endif + +#ifndef SvUVXx +# define SvUVXx(sv) SvUVX(sv) +#endif + +#ifndef SvUV +# define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv)) +#endif + +#ifndef SvUVx +# define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv)) +#endif + +/* Hint: sv_uv + * Always use the SvUVx() macro instead of sv_uv(). + */ +#ifndef sv_uv +# define sv_uv(sv) SvUVx(sv) +#endif + +#if !defined(SvUOK) && defined(SvIOK_UV) +# define SvUOK(sv) SvIOK_UV(sv) +#endif +#ifndef XST_mUV +# define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) ) +#endif + +#ifndef XSRETURN_UV +# define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END +#endif +#ifndef PUSHu +# define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END +#endif + +#ifndef XPUSHu +# define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END +#endif + +#ifdef HAS_MEMCMP +#ifndef memNE +# define memNE(s1,s2,l) (memcmp(s1,s2,l)) +#endif + +#ifndef memEQ +# define memEQ(s1,s2,l) (!memcmp(s1,s2,l)) +#endif + +#else +#ifndef memNE +# define memNE(s1,s2,l) (bcmp(s1,s2,l)) +#endif + +#ifndef memEQ +# define memEQ(s1,s2,l) (!bcmp(s1,s2,l)) +#endif + +#endif +#ifndef MoveD +# define MoveD(s,d,n,t) memmove((char*)(d),(char*)(s), (n) * sizeof(t)) +#endif + +#ifndef CopyD +# define CopyD(s,d,n,t) memcpy((char*)(d),(char*)(s), (n) * sizeof(t)) +#endif + +#ifdef HAS_MEMSET +#ifndef ZeroD +# define ZeroD(d,n,t) memzero((char*)(d), (n) * sizeof(t)) +#endif + +#else +#ifndef ZeroD +# define ZeroD(d,n,t) ((void)memzero((char*)(d), (n) * sizeof(t)), d) +#endif + +#endif +#ifndef PoisonWith +# define PoisonWith(d,n,t,b) (void)memset((char*)(d), (U8)(b), (n) * sizeof(t)) +#endif + +#ifndef PoisonNew +# define PoisonNew(d,n,t) PoisonWith(d,n,t,0xAB) +#endif + +#ifndef PoisonFree +# define PoisonFree(d,n,t) PoisonWith(d,n,t,0xEF) +#endif + +#ifndef Poison +# define Poison(d,n,t) PoisonFree(d,n,t) +#endif +#ifndef Newx +# define Newx(v,n,t) New(0,v,n,t) +#endif + +#ifndef Newxc +# define Newxc(v,n,t,c) Newc(0,v,n,t,c) +#endif + +#ifndef Newxz +# define Newxz(v,n,t) Newz(0,v,n,t) +#endif + +#ifndef PERL_UNUSED_DECL +# ifdef HASATTRIBUTE +# if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER) +# define PERL_UNUSED_DECL +# else +# define PERL_UNUSED_DECL __attribute__((unused)) +# endif +# else +# define PERL_UNUSED_DECL +# endif +#endif + +#ifndef PERL_UNUSED_ARG +# if defined(lint) && defined(S_SPLINT_S) /* www.splint.org */ +# include +# define PERL_UNUSED_ARG(x) NOTE(ARGUNUSED(x)) +# else +# define PERL_UNUSED_ARG(x) ((void)x) +# endif +#endif + +#ifndef PERL_UNUSED_VAR +# define PERL_UNUSED_VAR(x) ((void)x) +#endif + +#ifndef PERL_UNUSED_CONTEXT +# ifdef USE_ITHREADS +# define PERL_UNUSED_CONTEXT PERL_UNUSED_ARG(my_perl) +# else +# define PERL_UNUSED_CONTEXT +# endif +#endif +#ifndef NOOP +# define NOOP /*EMPTY*/(void)0 +#endif + +#ifndef dNOOP +# define dNOOP extern int /*@unused@*/ Perl___notused PERL_UNUSED_DECL +#endif + +#ifndef NVTYPE +# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) +# define NVTYPE long double +# else +# define NVTYPE double +# endif +typedef NVTYPE NV; +#endif + +#ifndef INT2PTR +# if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE) +# define PTRV UV +# define INT2PTR(any,d) (any)(d) +# else +# if PTRSIZE == LONGSIZE +# define PTRV unsigned long +# else +# define PTRV unsigned +# endif +# define INT2PTR(any,d) (any)(PTRV)(d) +# endif +#endif + +#ifndef PTR2ul +# if PTRSIZE == LONGSIZE +# define PTR2ul(p) (unsigned long)(p) +# else +# define PTR2ul(p) INT2PTR(unsigned long,p) +# endif +#endif +#ifndef PTR2nat +# define PTR2nat(p) (PTRV)(p) +#endif + +#ifndef NUM2PTR +# define NUM2PTR(any,d) (any)PTR2nat(d) +#endif + +#ifndef PTR2IV +# define PTR2IV(p) INT2PTR(IV,p) +#endif + +#ifndef PTR2UV +# define PTR2UV(p) INT2PTR(UV,p) +#endif + +#ifndef PTR2NV +# define PTR2NV(p) NUM2PTR(NV,p) +#endif + +#undef START_EXTERN_C +#undef END_EXTERN_C +#undef EXTERN_C +#ifdef __cplusplus +# define START_EXTERN_C extern "C" { +# define END_EXTERN_C } +# define EXTERN_C extern "C" +#else +# define START_EXTERN_C +# define END_EXTERN_C +# define EXTERN_C extern +#endif + +#if defined(PERL_GCC_PEDANTIC) +# ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN +# define PERL_GCC_BRACE_GROUPS_FORBIDDEN +# endif +#endif + +#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) +# ifndef PERL_USE_GCC_BRACE_GROUPS +# define PERL_USE_GCC_BRACE_GROUPS +# endif +#endif + +#undef STMT_START +#undef STMT_END +#ifdef PERL_USE_GCC_BRACE_GROUPS +# define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */ +# define STMT_END ) +#else +# if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) +# define STMT_START if (1) +# define STMT_END else (void)0 +# else +# define STMT_START do +# define STMT_END while (0) +# endif +#endif +#ifndef boolSV +# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) +#endif + +/* DEFSV appears first in 5.004_56 */ +#ifndef DEFSV +# define DEFSV GvSV(PL_defgv) +#endif + +#ifndef SAVE_DEFSV +# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv)) +#endif + +#ifndef DEFSV_set +# define DEFSV_set(sv) (DEFSV = (sv)) +#endif + +/* Older perls (<=5.003) lack AvFILLp */ +#ifndef AvFILLp +# define AvFILLp AvFILL +#endif +#ifndef ERRSV +# define ERRSV get_sv("@",FALSE) +#endif + +/* Hint: gv_stashpvn + * This function's backport doesn't support the length parameter, but + * rather ignores it. Portability can only be ensured if the length + * parameter is used for speed reasons, but the length can always be + * correctly computed from the string argument. + */ +#ifndef gv_stashpvn +# define gv_stashpvn(str,len,create) gv_stashpv(str,create) +#endif + +/* Replace: 1 */ +#ifndef get_cv +# define get_cv perl_get_cv +#endif + +#ifndef get_sv +# define get_sv perl_get_sv +#endif + +#ifndef get_av +# define get_av perl_get_av +#endif + +#ifndef get_hv +# define get_hv perl_get_hv +#endif + +/* Replace: 0 */ +#ifndef dUNDERBAR +# define dUNDERBAR dNOOP +#endif + +#ifndef UNDERBAR +# define UNDERBAR DEFSV +#endif +#ifndef dAX +# define dAX I32 ax = MARK - PL_stack_base + 1 +#endif + +#ifndef dITEMS +# define dITEMS I32 items = SP - MARK +#endif +#ifndef dXSTARG +# define dXSTARG SV * targ = sv_newmortal() +#endif +#ifndef dAXMARK +# define dAXMARK I32 ax = POPMARK; \ + register SV ** const mark = PL_stack_base + ax++ +#endif +#ifndef XSprePUSH +# define XSprePUSH (sp = PL_stack_base + ax - 1) +#endif + +#if (PERL_BCDVERSION < 0x5005000) +# undef XSRETURN +# define XSRETURN(off) \ + STMT_START { \ + PL_stack_sp = PL_stack_base + ax + ((off) - 1); \ + return; \ + } STMT_END +#endif +#ifndef XSPROTO +# define XSPROTO(name) void name(pTHX_ CV* cv) +#endif + +#ifndef SVfARG +# define SVfARG(p) ((void*)(p)) +#endif +#ifndef PERL_ABS +# define PERL_ABS(x) ((x) < 0 ? -(x) : (x)) +#endif +#ifndef dVAR +# define dVAR dNOOP +#endif +#ifndef SVf +# define SVf "_" +#endif +#ifndef UTF8_MAXBYTES +# define UTF8_MAXBYTES UTF8_MAXLEN +#endif +#ifndef CPERLscope +# define CPERLscope(x) x +#endif +#ifndef PERL_HASH +# define PERL_HASH(hash,str,len) \ + STMT_START { \ + const char *s_PeRlHaSh = str; \ + I32 i_PeRlHaSh = len; \ + U32 hash_PeRlHaSh = 0; \ + while (i_PeRlHaSh--) \ + hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \ + (hash) = hash_PeRlHaSh; \ + } STMT_END +#endif + +#ifndef PERLIO_FUNCS_DECL +# ifdef PERLIO_FUNCS_CONST +# define PERLIO_FUNCS_DECL(funcs) const PerlIO_funcs funcs +# define PERLIO_FUNCS_CAST(funcs) (PerlIO_funcs*)(funcs) +# else +# define PERLIO_FUNCS_DECL(funcs) PerlIO_funcs funcs +# define PERLIO_FUNCS_CAST(funcs) (funcs) +# endif +#endif + +/* provide these typedefs for older perls */ +#if (PERL_BCDVERSION < 0x5009003) + +# ifdef ARGSproto +typedef OP* (CPERLscope(*Perl_ppaddr_t))(ARGSproto); +# else +typedef OP* (CPERLscope(*Perl_ppaddr_t))(pTHX); +# endif + +typedef OP* (CPERLscope(*Perl_check_t)) (pTHX_ OP*); + +#endif +#ifndef isPSXSPC +# define isPSXSPC(c) (isSPACE(c) || (c) == '\v') +#endif + +#ifndef isBLANK +# define isBLANK(c) ((c) == ' ' || (c) == '\t') +#endif + +#ifdef EBCDIC +#ifndef isALNUMC +# define isALNUMC(c) isalnum(c) +#endif + +#ifndef isASCII +# define isASCII(c) isascii(c) +#endif + +#ifndef isCNTRL +# define isCNTRL(c) iscntrl(c) +#endif + +#ifndef isGRAPH +# define isGRAPH(c) isgraph(c) +#endif + +#ifndef isPRINT +# define isPRINT(c) isprint(c) +#endif + +#ifndef isPUNCT +# define isPUNCT(c) ispunct(c) +#endif + +#ifndef isXDIGIT +# define isXDIGIT(c) isxdigit(c) +#endif + +#else +# if (PERL_BCDVERSION < 0x5010000) +/* Hint: isPRINT + * The implementation in older perl versions includes all of the + * isSPACE() characters, which is wrong. The version provided by + * Devel::PPPort always overrides a present buggy version. + */ +# undef isPRINT +# endif +#ifndef isALNUMC +# define isALNUMC(c) (isALPHA(c) || isDIGIT(c)) +#endif + +#ifndef isASCII +# define isASCII(c) ((c) <= 127) +#endif + +#ifndef isCNTRL +# define isCNTRL(c) ((c) < ' ' || (c) == 127) +#endif + +#ifndef isGRAPH +# define isGRAPH(c) (isALNUM(c) || isPUNCT(c)) +#endif + +#ifndef isPRINT +# define isPRINT(c) (((c) >= 32 && (c) < 127)) +#endif + +#ifndef isPUNCT +# define isPUNCT(c) (((c) >= 33 && (c) <= 47) || ((c) >= 58 && (c) <= 64) || ((c) >= 91 && (c) <= 96) || ((c) >= 123 && (c) <= 126)) +#endif + +#ifndef isXDIGIT +# define isXDIGIT(c) (isDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +#endif + +#ifndef PERL_SIGNALS_UNSAFE_FLAG + +#define PERL_SIGNALS_UNSAFE_FLAG 0x0001 + +#if (PERL_BCDVERSION < 0x5008000) +# define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG +#else +# define D_PPP_PERL_SIGNALS_INIT 0 +#endif + +#if defined(NEED_PL_signals) +static U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; +#elif defined(NEED_PL_signals_GLOBAL) +U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; +#else +extern U32 DPPP_(my_PL_signals); +#endif +#define PL_signals DPPP_(my_PL_signals) + +#endif + +/* Hint: PL_ppaddr + * Calling an op via PL_ppaddr requires passing a context argument + * for threaded builds. Since the context argument is different for + * 5.005 perls, you can use aTHXR (supplied by ppport.h), which will + * automatically be defined as the correct argument. + */ + +#if (PERL_BCDVERSION <= 0x5005005) +/* Replace: 1 */ +# define PL_ppaddr ppaddr +# define PL_no_modify no_modify +/* Replace: 0 */ +#endif + +#if (PERL_BCDVERSION <= 0x5004005) +/* Replace: 1 */ +# define PL_DBsignal DBsignal +# define PL_DBsingle DBsingle +# define PL_DBsub DBsub +# define PL_DBtrace DBtrace +# define PL_Sv Sv +# define PL_bufend bufend +# define PL_bufptr bufptr +# define PL_compiling compiling +# define PL_copline copline +# define PL_curcop curcop +# define PL_curstash curstash +# define PL_debstash debstash +# define PL_defgv defgv +# define PL_diehook diehook +# define PL_dirty dirty +# define PL_dowarn dowarn +# define PL_errgv errgv +# define PL_error_count error_count +# define PL_expect expect +# define PL_hexdigit hexdigit +# define PL_hints hints +# define PL_in_my in_my +# define PL_laststatval laststatval +# define PL_lex_state lex_state +# define PL_lex_stuff lex_stuff +# define PL_linestr linestr +# define PL_na na +# define PL_perl_destruct_level perl_destruct_level +# define PL_perldb perldb +# define PL_rsfp_filters rsfp_filters +# define PL_rsfp rsfp +# define PL_stack_base stack_base +# define PL_stack_sp stack_sp +# define PL_statcache statcache +# define PL_stdingv stdingv +# define PL_sv_arenaroot sv_arenaroot +# define PL_sv_no sv_no +# define PL_sv_undef sv_undef +# define PL_sv_yes sv_yes +# define PL_tainted tainted +# define PL_tainting tainting +# define PL_tokenbuf tokenbuf +/* Replace: 0 */ +#endif + +/* Warning: PL_parser + * For perl versions earlier than 5.9.5, this is an always + * non-NULL dummy. Also, it cannot be dereferenced. Don't + * use it if you can avoid is and unless you absolutely know + * what you're doing. + * If you always check that PL_parser is non-NULL, you can + * define DPPP_PL_parser_NO_DUMMY to avoid the creation of + * a dummy parser structure. + */ + +#if (PERL_BCDVERSION >= 0x5009005) +# ifdef DPPP_PL_parser_NO_DUMMY +# define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ + (croak("panic: PL_parser == NULL in %s:%d", \ + __FILE__, __LINE__), (yy_parser *) NULL))->var) +# else +# ifdef DPPP_PL_parser_NO_DUMMY_WARNING +# define D_PPP_parser_dummy_warning(var) +# else +# define D_PPP_parser_dummy_warning(var) \ + warn("warning: dummy PL_" #var " used in %s:%d", __FILE__, __LINE__), +# endif +# define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ + (D_PPP_parser_dummy_warning(var) &DPPP_(dummy_PL_parser)))->var) +#if defined(NEED_PL_parser) +static yy_parser DPPP_(dummy_PL_parser); +#elif defined(NEED_PL_parser_GLOBAL) +yy_parser DPPP_(dummy_PL_parser); +#else +extern yy_parser DPPP_(dummy_PL_parser); +#endif + +# endif + +/* PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf depends on PL_parser */ +/* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf + * Do not use this variable unless you know exactly what you're + * doint. It is internal to the perl parser and may change or even + * be removed in the future. As of perl 5.9.5, you have to check + * for (PL_parser != NULL) for this variable to have any effect. + * An always non-NULL PL_parser dummy is provided for earlier + * perl versions. + * If PL_parser is NULL when you try to access this variable, a + * dummy is being accessed instead and a warning is issued unless + * you define DPPP_PL_parser_NO_DUMMY_WARNING. + * If DPPP_PL_parser_NO_DUMMY is defined, the code trying to access + * this variable will croak with a panic message. + */ + +# define PL_expect D_PPP_my_PL_parser_var(expect) +# define PL_copline D_PPP_my_PL_parser_var(copline) +# define PL_rsfp D_PPP_my_PL_parser_var(rsfp) +# define PL_rsfp_filters D_PPP_my_PL_parser_var(rsfp_filters) +# define PL_linestr D_PPP_my_PL_parser_var(linestr) +# define PL_bufptr D_PPP_my_PL_parser_var(bufptr) +# define PL_bufend D_PPP_my_PL_parser_var(bufend) +# define PL_lex_state D_PPP_my_PL_parser_var(lex_state) +# define PL_lex_stuff D_PPP_my_PL_parser_var(lex_stuff) +# define PL_tokenbuf D_PPP_my_PL_parser_var(tokenbuf) +# define PL_in_my D_PPP_my_PL_parser_var(in_my) +# define PL_in_my_stash D_PPP_my_PL_parser_var(in_my_stash) +# define PL_error_count D_PPP_my_PL_parser_var(error_count) + + +#else + +/* ensure that PL_parser != NULL and cannot be dereferenced */ +# define PL_parser ((void *) 1) + +#endif +#ifndef mPUSHs +# define mPUSHs(s) PUSHs(sv_2mortal(s)) +#endif + +#ifndef PUSHmortal +# define PUSHmortal PUSHs(sv_newmortal()) +#endif + +#ifndef mPUSHp +# define mPUSHp(p,l) sv_setpvn(PUSHmortal, (p), (l)) +#endif + +#ifndef mPUSHn +# define mPUSHn(n) sv_setnv(PUSHmortal, (NV)(n)) +#endif + +#ifndef mPUSHi +# define mPUSHi(i) sv_setiv(PUSHmortal, (IV)(i)) +#endif + +#ifndef mPUSHu +# define mPUSHu(u) sv_setuv(PUSHmortal, (UV)(u)) +#endif +#ifndef mXPUSHs +# define mXPUSHs(s) XPUSHs(sv_2mortal(s)) +#endif + +#ifndef XPUSHmortal +# define XPUSHmortal XPUSHs(sv_newmortal()) +#endif + +#ifndef mXPUSHp +# define mXPUSHp(p,l) STMT_START { EXTEND(sp,1); sv_setpvn(PUSHmortal, (p), (l)); } STMT_END +#endif + +#ifndef mXPUSHn +# define mXPUSHn(n) STMT_START { EXTEND(sp,1); sv_setnv(PUSHmortal, (NV)(n)); } STMT_END +#endif + +#ifndef mXPUSHi +# define mXPUSHi(i) STMT_START { EXTEND(sp,1); sv_setiv(PUSHmortal, (IV)(i)); } STMT_END +#endif + +#ifndef mXPUSHu +# define mXPUSHu(u) STMT_START { EXTEND(sp,1); sv_setuv(PUSHmortal, (UV)(u)); } STMT_END +#endif + +/* Replace: 1 */ +#ifndef call_sv +# define call_sv perl_call_sv +#endif + +#ifndef call_pv +# define call_pv perl_call_pv +#endif + +#ifndef call_argv +# define call_argv perl_call_argv +#endif + +#ifndef call_method +# define call_method perl_call_method +#endif +#ifndef eval_sv +# define eval_sv perl_eval_sv +#endif + +/* Replace: 0 */ +#ifndef PERL_LOADMOD_DENY +# define PERL_LOADMOD_DENY 0x1 +#endif + +#ifndef PERL_LOADMOD_NOIMPORT +# define PERL_LOADMOD_NOIMPORT 0x2 +#endif + +#ifndef PERL_LOADMOD_IMPORT_OPS +# define PERL_LOADMOD_IMPORT_OPS 0x4 +#endif + +#ifndef G_METHOD +# define G_METHOD 64 +# ifdef call_sv +# undef call_sv +# endif +# if (PERL_BCDVERSION < 0x5006000) +# define call_sv(sv, flags) ((flags) & G_METHOD ? perl_call_method((char *) SvPV_nolen_const(sv), \ + (flags) & ~G_METHOD) : perl_call_sv(sv, flags)) +# else +# define call_sv(sv, flags) ((flags) & G_METHOD ? Perl_call_method(aTHX_ (char *) SvPV_nolen_const(sv), \ + (flags) & ~G_METHOD) : Perl_call_sv(aTHX_ sv, flags)) +# endif +#endif + +/* Replace perl_eval_pv with eval_pv */ + +#ifndef eval_pv +#if defined(NEED_eval_pv) +static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); +static +#else +extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); +#endif + +#ifdef eval_pv +# undef eval_pv +#endif +#define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b) +#define Perl_eval_pv DPPP_(my_eval_pv) + +#if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL) + +SV* +DPPP_(my_eval_pv)(char *p, I32 croak_on_error) +{ + dSP; + SV* sv = newSVpv(p, 0); + + PUSHMARK(sp); + eval_sv(sv, G_SCALAR); + SvREFCNT_dec(sv); + + SPAGAIN; + sv = POPs; + PUTBACK; + + if (croak_on_error && SvTRUE(GvSV(errgv))) + croak(SvPVx(GvSV(errgv), na)); + + return sv; +} + +#endif +#endif + +#ifndef vload_module +#if defined(NEED_vload_module) +static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); +static +#else +extern void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); +#endif + +#ifdef vload_module +# undef vload_module +#endif +#define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d) +#define Perl_vload_module DPPP_(my_vload_module) + +#if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL) + +void +DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args) +{ + dTHR; + dVAR; + OP *veop, *imop; + + OP * const modname = newSVOP(OP_CONST, 0, name); + /* 5.005 has a somewhat hacky force_normal that doesn't croak on + SvREADONLY() if PL_compling is true. Current perls take care in + ck_require() to correctly turn off SvREADONLY before calling + force_normal_flags(). This seems a better fix than fudging PL_compling + */ + SvREADONLY_off(((SVOP*)modname)->op_sv); + modname->op_private |= OPpCONST_BARE; + if (ver) { + veop = newSVOP(OP_CONST, 0, ver); + } + else + veop = NULL; + if (flags & PERL_LOADMOD_NOIMPORT) { + imop = sawparens(newNULLLIST()); + } + else if (flags & PERL_LOADMOD_IMPORT_OPS) { + imop = va_arg(*args, OP*); + } + else { + SV *sv; + imop = NULL; + sv = va_arg(*args, SV*); + while (sv) { + imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv)); + sv = va_arg(*args, SV*); + } + } + { + const line_t ocopline = PL_copline; + COP * const ocurcop = PL_curcop; + const int oexpect = PL_expect; + +#if (PERL_BCDVERSION >= 0x5004000) + utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0), + veop, modname, imop); +#else + utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(), + modname, imop); +#endif + PL_expect = oexpect; + PL_copline = ocopline; + PL_curcop = ocurcop; + } +} + +#endif +#endif + +#ifndef load_module +#if defined(NEED_load_module) +static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); +static +#else +extern void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); +#endif + +#ifdef load_module +# undef load_module +#endif +#define load_module DPPP_(my_load_module) +#define Perl_load_module DPPP_(my_load_module) + +#if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL) + +void +DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...) +{ + va_list args; + va_start(args, ver); + vload_module(flags, name, ver, &args); + va_end(args); +} + +#endif +#endif +#ifndef newRV_inc +# define newRV_inc(sv) newRV(sv) /* Replace */ +#endif + +#ifndef newRV_noinc +#if defined(NEED_newRV_noinc) +static SV * DPPP_(my_newRV_noinc)(SV *sv); +static +#else +extern SV * DPPP_(my_newRV_noinc)(SV *sv); +#endif + +#ifdef newRV_noinc +# undef newRV_noinc +#endif +#define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a) +#define Perl_newRV_noinc DPPP_(my_newRV_noinc) + +#if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL) +SV * +DPPP_(my_newRV_noinc)(SV *sv) +{ + SV *rv = (SV *)newRV(sv); + SvREFCNT_dec(sv); + return rv; +} +#endif +#endif + +/* Hint: newCONSTSUB + * Returns a CV* as of perl-5.7.1. This return value is not supported + * by Devel::PPPort. + */ + +/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */ +#if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005) +#if defined(NEED_newCONSTSUB) +static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); +static +#else +extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); +#endif + +#ifdef newCONSTSUB +# undef newCONSTSUB +#endif +#define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c) +#define Perl_newCONSTSUB DPPP_(my_newCONSTSUB) + +#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL) + +/* This is just a trick to avoid a dependency of newCONSTSUB on PL_parser */ +/* (There's no PL_parser in perl < 5.005, so this is completely safe) */ +#define D_PPP_PL_copline PL_copline + +void +DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv) +{ + U32 oldhints = PL_hints; + HV *old_cop_stash = PL_curcop->cop_stash; + HV *old_curstash = PL_curstash; + line_t oldline = PL_curcop->cop_line; + PL_curcop->cop_line = D_PPP_PL_copline; + + PL_hints &= ~HINT_BLOCK_SCOPE; + if (stash) + PL_curstash = PL_curcop->cop_stash = stash; + + newSUB( + +#if (PERL_BCDVERSION < 0x5003022) + start_subparse(), +#elif (PERL_BCDVERSION == 0x5003022) + start_subparse(0), +#else /* 5.003_23 onwards */ + start_subparse(FALSE, 0), +#endif + + newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)), + newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */ + newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv)) + ); + + PL_hints = oldhints; + PL_curcop->cop_stash = old_cop_stash; + PL_curstash = old_curstash; + PL_curcop->cop_line = oldline; +} +#endif +#endif + +/* + * Boilerplate macros for initializing and accessing interpreter-local + * data from C. All statics in extensions should be reworked to use + * this, if you want to make the extension thread-safe. See ext/re/re.xs + * for an example of the use of these macros. + * + * Code that uses these macros is responsible for the following: + * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts" + * 2. Declare a typedef named my_cxt_t that is a structure that contains + * all the data that needs to be interpreter-local. + * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t. + * 4. Use the MY_CXT_INIT macro such that it is called exactly once + * (typically put in the BOOT: section). + * 5. Use the members of the my_cxt_t structure everywhere as + * MY_CXT.member. + * 6. Use the dMY_CXT macro (a declaration) in all the functions that + * access MY_CXT. + */ + +#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \ + defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT) + +#ifndef START_MY_CXT + +/* This must appear in all extensions that define a my_cxt_t structure, + * right after the definition (i.e. at file scope). The non-threads + * case below uses it to declare the data as static. */ +#define START_MY_CXT + +#if (PERL_BCDVERSION < 0x5004068) +/* Fetches the SV that keeps the per-interpreter data. */ +#define dMY_CXT_SV \ + SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE) +#else /* >= perl5.004_68 */ +#define dMY_CXT_SV \ + SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \ + sizeof(MY_CXT_KEY)-1, TRUE) +#endif /* < perl5.004_68 */ + +/* This declaration should be used within all functions that use the + * interpreter-local data. */ +#define dMY_CXT \ + dMY_CXT_SV; \ + my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv)) + +/* Creates and zeroes the per-interpreter data. + * (We allocate my_cxtp in a Perl SV so that it will be released when + * the interpreter goes away.) */ +#define MY_CXT_INIT \ + dMY_CXT_SV; \ + /* newSV() allocates one more than needed */ \ + my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ + Zero(my_cxtp, 1, my_cxt_t); \ + sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) + +/* This macro must be used to access members of the my_cxt_t structure. + * e.g. MYCXT.some_data */ +#define MY_CXT (*my_cxtp) + +/* Judicious use of these macros can reduce the number of times dMY_CXT + * is used. Use is similar to pTHX, aTHX etc. */ +#define pMY_CXT my_cxt_t *my_cxtp +#define pMY_CXT_ pMY_CXT, +#define _pMY_CXT ,pMY_CXT +#define aMY_CXT my_cxtp +#define aMY_CXT_ aMY_CXT, +#define _aMY_CXT ,aMY_CXT + +#endif /* START_MY_CXT */ + +#ifndef MY_CXT_CLONE +/* Clones the per-interpreter data. */ +#define MY_CXT_CLONE \ + dMY_CXT_SV; \ + my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ + Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\ + sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) +#endif + +#else /* single interpreter */ + +#ifndef START_MY_CXT + +#define START_MY_CXT static my_cxt_t my_cxt; +#define dMY_CXT_SV dNOOP +#define dMY_CXT dNOOP +#define MY_CXT_INIT NOOP +#define MY_CXT my_cxt + +#define pMY_CXT void +#define pMY_CXT_ +#define _pMY_CXT +#define aMY_CXT +#define aMY_CXT_ +#define _aMY_CXT + +#endif /* START_MY_CXT */ + +#ifndef MY_CXT_CLONE +#define MY_CXT_CLONE NOOP +#endif + +#endif + +#ifndef IVdf +# if IVSIZE == LONGSIZE +# define IVdf "ld" +# define UVuf "lu" +# define UVof "lo" +# define UVxf "lx" +# define UVXf "lX" +# else +# if IVSIZE == INTSIZE +# define IVdf "d" +# define UVuf "u" +# define UVof "o" +# define UVxf "x" +# define UVXf "X" +# endif +# endif +#endif + +#ifndef NVef +# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \ + defined(PERL_PRIfldbl) && (PERL_BCDVERSION != 0x5006000) + /* Not very likely, but let's try anyway. */ +# define NVef PERL_PRIeldbl +# define NVff PERL_PRIfldbl +# define NVgf PERL_PRIgldbl +# else +# define NVef "e" +# define NVff "f" +# define NVgf "g" +# endif +#endif + +#ifndef SvREFCNT_inc +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define SvREFCNT_inc(sv) \ + ({ \ + SV * const _sv = (SV*)(sv); \ + if (_sv) \ + (SvREFCNT(_sv))++; \ + _sv; \ + }) +# else +# define SvREFCNT_inc(sv) \ + ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) +# endif +#endif + +#ifndef SvREFCNT_inc_simple +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define SvREFCNT_inc_simple(sv) \ + ({ \ + if (sv) \ + (SvREFCNT(sv))++; \ + (SV *)(sv); \ + }) +# else +# define SvREFCNT_inc_simple(sv) \ + ((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL) +# endif +#endif + +#ifndef SvREFCNT_inc_NN +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define SvREFCNT_inc_NN(sv) \ + ({ \ + SV * const _sv = (SV*)(sv); \ + SvREFCNT(_sv)++; \ + _sv; \ + }) +# else +# define SvREFCNT_inc_NN(sv) \ + (PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv) +# endif +#endif + +#ifndef SvREFCNT_inc_void +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define SvREFCNT_inc_void(sv) \ + ({ \ + SV * const _sv = (SV*)(sv); \ + if (_sv) \ + (void)(SvREFCNT(_sv)++); \ + }) +# else +# define SvREFCNT_inc_void(sv) \ + (void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0) +# endif +#endif +#ifndef SvREFCNT_inc_simple_void +# define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END +#endif + +#ifndef SvREFCNT_inc_simple_NN +# define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv)) +#endif + +#ifndef SvREFCNT_inc_void_NN +# define SvREFCNT_inc_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) +#endif + +#ifndef SvREFCNT_inc_simple_void_NN +# define SvREFCNT_inc_simple_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) +#endif + +#ifndef newSV_type + +#if defined(NEED_newSV_type) +static SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); +static +#else +extern SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); +#endif + +#ifdef newSV_type +# undef newSV_type +#endif +#define newSV_type(a) DPPP_(my_newSV_type)(aTHX_ a) +#define Perl_newSV_type DPPP_(my_newSV_type) + +#if defined(NEED_newSV_type) || defined(NEED_newSV_type_GLOBAL) + +SV* +DPPP_(my_newSV_type)(pTHX_ svtype const t) +{ + SV* const sv = newSV(0); + sv_upgrade(sv, t); + return sv; +} + +#endif + +#endif + +#if (PERL_BCDVERSION < 0x5006000) +# define D_PPP_CONSTPV_ARG(x) ((char *) (x)) +#else +# define D_PPP_CONSTPV_ARG(x) (x) +#endif +#ifndef newSVpvn +# define newSVpvn(data,len) ((data) \ + ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \ + : newSV(0)) +#endif +#ifndef newSVpvn_utf8 +# define newSVpvn_utf8(s, len, u) newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0) +#endif +#ifndef SVf_UTF8 +# define SVf_UTF8 0 +#endif + +#ifndef newSVpvn_flags + +#if defined(NEED_newSVpvn_flags) +static SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); +static +#else +extern SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); +#endif + +#ifdef newSVpvn_flags +# undef newSVpvn_flags +#endif +#define newSVpvn_flags(a,b,c) DPPP_(my_newSVpvn_flags)(aTHX_ a,b,c) +#define Perl_newSVpvn_flags DPPP_(my_newSVpvn_flags) + +#if defined(NEED_newSVpvn_flags) || defined(NEED_newSVpvn_flags_GLOBAL) + +SV * +DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags) +{ + SV *sv = newSVpvn(D_PPP_CONSTPV_ARG(s), len); + SvFLAGS(sv) |= (flags & SVf_UTF8); + return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv; +} + +#endif + +#endif + +/* Backwards compatibility stuff... :-( */ +#if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen) +# define NEED_sv_2pv_flags +#endif +#if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL) +# define NEED_sv_2pv_flags_GLOBAL +#endif + +/* Hint: sv_2pv_nolen + * Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen(). + */ +#ifndef sv_2pv_nolen +# define sv_2pv_nolen(sv) SvPV_nolen(sv) +#endif + +#ifdef SvPVbyte + +/* Hint: SvPVbyte + * Does not work in perl-5.6.1, ppport.h implements a version + * borrowed from perl-5.7.3. + */ + +#if (PERL_BCDVERSION < 0x5007000) + +#if defined(NEED_sv_2pvbyte) +static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); +static +#else +extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); +#endif + +#ifdef sv_2pvbyte +# undef sv_2pvbyte +#endif +#define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b) +#define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte) + +#if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL) + +char * +DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp) +{ + sv_utf8_downgrade(sv,0); + return SvPV(sv,*lp); +} + +#endif + +/* Hint: sv_2pvbyte + * Use the SvPVbyte() macro instead of sv_2pvbyte(). + */ + +#undef SvPVbyte + +#define SvPVbyte(sv, lp) \ + ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \ + ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp)) + +#endif + +#else + +# define SvPVbyte SvPV +# define sv_2pvbyte sv_2pv + +#endif +#ifndef sv_2pvbyte_nolen +# define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv) +#endif + +/* Hint: sv_pvn + * Always use the SvPV() macro instead of sv_pvn(). + */ + +/* Hint: sv_pvn_force + * Always use the SvPV_force() macro instead of sv_pvn_force(). + */ + +/* If these are undefined, they're not handled by the core anyway */ +#ifndef SV_IMMEDIATE_UNREF +# define SV_IMMEDIATE_UNREF 0 +#endif + +#ifndef SV_GMAGIC +# define SV_GMAGIC 0 +#endif + +#ifndef SV_COW_DROP_PV +# define SV_COW_DROP_PV 0 +#endif + +#ifndef SV_UTF8_NO_ENCODING +# define SV_UTF8_NO_ENCODING 0 +#endif + +#ifndef SV_NOSTEAL +# define SV_NOSTEAL 0 +#endif + +#ifndef SV_CONST_RETURN +# define SV_CONST_RETURN 0 +#endif + +#ifndef SV_MUTABLE_RETURN +# define SV_MUTABLE_RETURN 0 +#endif + +#ifndef SV_SMAGIC +# define SV_SMAGIC 0 +#endif + +#ifndef SV_HAS_TRAILING_NUL +# define SV_HAS_TRAILING_NUL 0 +#endif + +#ifndef SV_COW_SHARED_HASH_KEYS +# define SV_COW_SHARED_HASH_KEYS 0 +#endif + +#if (PERL_BCDVERSION < 0x5007002) + +#if defined(NEED_sv_2pv_flags) +static char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); +static +#else +extern char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); +#endif + +#ifdef sv_2pv_flags +# undef sv_2pv_flags +#endif +#define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c) +#define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags) + +#if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL) + +char * +DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) +{ + STRLEN n_a = (STRLEN) flags; + return sv_2pv(sv, lp ? lp : &n_a); +} + +#endif + +#if defined(NEED_sv_pvn_force_flags) +static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); +static +#else +extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); +#endif + +#ifdef sv_pvn_force_flags +# undef sv_pvn_force_flags +#endif +#define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c) +#define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags) + +#if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL) + +char * +DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) +{ + STRLEN n_a = (STRLEN) flags; + return sv_pvn_force(sv, lp ? lp : &n_a); +} + +#endif + +#endif + +#if (PERL_BCDVERSION < 0x5008008) || ( (PERL_BCDVERSION >= 0x5009000) && (PERL_BCDVERSION < 0x5009003) ) +# define DPPP_SVPV_NOLEN_LP_ARG &PL_na +#else +# define DPPP_SVPV_NOLEN_LP_ARG 0 +#endif +#ifndef SvPV_const +# define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC) +#endif + +#ifndef SvPV_mutable +# define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC) +#endif +#ifndef SvPV_flags +# define SvPV_flags(sv, lp, flags) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags)) +#endif +#ifndef SvPV_flags_const +# define SvPV_flags_const(sv, lp, flags) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \ + (const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN)) +#endif +#ifndef SvPV_flags_const_nolen +# define SvPV_flags_const_nolen(sv, flags) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? SvPVX_const(sv) : \ + (const char*) sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags|SV_CONST_RETURN)) +#endif +#ifndef SvPV_flags_mutable +# define SvPV_flags_mutable(sv, lp, flags) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \ + sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) +#endif +#ifndef SvPV_force +# define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC) +#endif + +#ifndef SvPV_force_nolen +# define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC) +#endif + +#ifndef SvPV_force_mutable +# define SvPV_force_mutable(sv, lp) SvPV_force_flags_mutable(sv, lp, SV_GMAGIC) +#endif + +#ifndef SvPV_force_nomg +# define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0) +#endif + +#ifndef SvPV_force_nomg_nolen +# define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0) +#endif +#ifndef SvPV_force_flags +# define SvPV_force_flags(sv, lp, flags) \ + ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ + ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags)) +#endif +#ifndef SvPV_force_flags_nolen +# define SvPV_force_flags_nolen(sv, flags) \ + ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ + ? SvPVX(sv) : sv_pvn_force_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags)) +#endif +#ifndef SvPV_force_flags_mutable +# define SvPV_force_flags_mutable(sv, lp, flags) \ + ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ + ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \ + : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) +#endif +#ifndef SvPV_nolen +# define SvPV_nolen(sv) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC)) +#endif +#ifndef SvPV_nolen_const +# define SvPV_nolen_const(sv) \ + ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ + ? SvPVX_const(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC|SV_CONST_RETURN)) +#endif +#ifndef SvPV_nomg +# define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0) +#endif + +#ifndef SvPV_nomg_const +# define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0) +#endif + +#ifndef SvPV_nomg_const_nolen +# define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0) +#endif +#ifndef SvPV_renew +# define SvPV_renew(sv,n) STMT_START { SvLEN_set(sv, n); \ + SvPV_set((sv), (char *) saferealloc( \ + (Malloc_t)SvPVX(sv), (MEM_SIZE)((n)))); \ + } STMT_END +#endif +#ifndef SvMAGIC_set +# define SvMAGIC_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ + (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END +#endif + +#if (PERL_BCDVERSION < 0x5009003) +#ifndef SvPVX_const +# define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv))) +#endif + +#ifndef SvPVX_mutable +# define SvPVX_mutable(sv) (0 + SvPVX(sv)) +#endif +#ifndef SvRV_set +# define SvRV_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ + (((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END +#endif + +#else +#ifndef SvPVX_const +# define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv)) +#endif + +#ifndef SvPVX_mutable +# define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv) +#endif +#ifndef SvRV_set +# define SvRV_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ + ((sv)->sv_u.svu_rv = (val)); } STMT_END +#endif + +#endif +#ifndef SvSTASH_set +# define SvSTASH_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ + (((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END +#endif + +#if (PERL_BCDVERSION < 0x5004000) +#ifndef SvUV_set +# define SvUV_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ + (((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END +#endif + +#else +#ifndef SvUV_set +# define SvUV_set(sv, val) \ + STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ + (((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END +#endif + +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf) +#if defined(NEED_vnewSVpvf) +static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); +static +#else +extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); +#endif + +#ifdef vnewSVpvf +# undef vnewSVpvf +#endif +#define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b) +#define Perl_vnewSVpvf DPPP_(my_vnewSVpvf) + +#if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL) + +SV * +DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args) +{ + register SV *sv = newSV(0); + sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); + return sv; +} + +#endif +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf) +# define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf) +# define sv_vsetpvf(sv, pat, args) sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg) +#if defined(NEED_sv_catpvf_mg) +static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); +static +#else +extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); +#endif + +#define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg) + +#if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL) + +void +DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...) +{ + va_list args; + va_start(args, pat); + sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); + SvSETMAGIC(sv); + va_end(args); +} + +#endif +#endif + +#ifdef PERL_IMPLICIT_CONTEXT +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext) +#if defined(NEED_sv_catpvf_mg_nocontext) +static void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); +static +#else +extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); +#endif + +#define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) +#define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) + +#if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL) + +void +DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...) +{ + dTHX; + va_list args; + va_start(args, pat); + sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); + SvSETMAGIC(sv); + va_end(args); +} + +#endif +#endif +#endif + +/* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */ +#ifndef sv_catpvf_mg +# ifdef PERL_IMPLICIT_CONTEXT +# define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext +# else +# define sv_catpvf_mg Perl_sv_catpvf_mg +# endif +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg) +# define sv_vcatpvf_mg(sv, pat, args) \ + STMT_START { \ + sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ + SvSETMAGIC(sv); \ + } STMT_END +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg) +#if defined(NEED_sv_setpvf_mg) +static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); +static +#else +extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); +#endif + +#define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg) + +#if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL) + +void +DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...) +{ + va_list args; + va_start(args, pat); + sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); + SvSETMAGIC(sv); + va_end(args); +} + +#endif +#endif + +#ifdef PERL_IMPLICIT_CONTEXT +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext) +#if defined(NEED_sv_setpvf_mg_nocontext) +static void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); +static +#else +extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); +#endif + +#define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) +#define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) + +#if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL) + +void +DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...) +{ + dTHX; + va_list args; + va_start(args, pat); + sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); + SvSETMAGIC(sv); + va_end(args); +} + +#endif +#endif +#endif + +/* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */ +#ifndef sv_setpvf_mg +# ifdef PERL_IMPLICIT_CONTEXT +# define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext +# else +# define sv_setpvf_mg Perl_sv_setpvf_mg +# endif +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg) +# define sv_vsetpvf_mg(sv, pat, args) \ + STMT_START { \ + sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ + SvSETMAGIC(sv); \ + } STMT_END +#endif + +#ifndef newSVpvn_share + +#if defined(NEED_newSVpvn_share) +static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); +static +#else +extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); +#endif + +#ifdef newSVpvn_share +# undef newSVpvn_share +#endif +#define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c) +#define Perl_newSVpvn_share DPPP_(my_newSVpvn_share) + +#if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL) + +SV * +DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash) +{ + SV *sv; + if (len < 0) + len = -len; + if (!hash) + PERL_HASH(hash, (char*) src, len); + sv = newSVpvn((char *) src, len); + sv_upgrade(sv, SVt_PVIV); + SvIVX(sv) = hash; + SvREADONLY_on(sv); + SvPOK_on(sv); + return sv; +} + +#endif + +#endif +#ifndef SvSHARED_HASH +# define SvSHARED_HASH(sv) (0 + SvUVX(sv)) +#endif +#ifndef HvNAME_get +# define HvNAME_get(hv) HvNAME(hv) +#endif +#ifndef HvNAMELEN_get +# define HvNAMELEN_get(hv) (HvNAME_get(hv) ? (I32)strlen(HvNAME_get(hv)) : 0) +#endif +#ifndef GvSVn +# define GvSVn(gv) GvSV(gv) +#endif + +#ifndef isGV_with_GP +# define isGV_with_GP(gv) isGV(gv) +#endif +#ifndef WARN_ALL +# define WARN_ALL 0 +#endif + +#ifndef WARN_CLOSURE +# define WARN_CLOSURE 1 +#endif + +#ifndef WARN_DEPRECATED +# define WARN_DEPRECATED 2 +#endif + +#ifndef WARN_EXITING +# define WARN_EXITING 3 +#endif + +#ifndef WARN_GLOB +# define WARN_GLOB 4 +#endif + +#ifndef WARN_IO +# define WARN_IO 5 +#endif + +#ifndef WARN_CLOSED +# define WARN_CLOSED 6 +#endif + +#ifndef WARN_EXEC +# define WARN_EXEC 7 +#endif + +#ifndef WARN_LAYER +# define WARN_LAYER 8 +#endif + +#ifndef WARN_NEWLINE +# define WARN_NEWLINE 9 +#endif + +#ifndef WARN_PIPE +# define WARN_PIPE 10 +#endif + +#ifndef WARN_UNOPENED +# define WARN_UNOPENED 11 +#endif + +#ifndef WARN_MISC +# define WARN_MISC 12 +#endif + +#ifndef WARN_NUMERIC +# define WARN_NUMERIC 13 +#endif + +#ifndef WARN_ONCE +# define WARN_ONCE 14 +#endif + +#ifndef WARN_OVERFLOW +# define WARN_OVERFLOW 15 +#endif + +#ifndef WARN_PACK +# define WARN_PACK 16 +#endif + +#ifndef WARN_PORTABLE +# define WARN_PORTABLE 17 +#endif + +#ifndef WARN_RECURSION +# define WARN_RECURSION 18 +#endif + +#ifndef WARN_REDEFINE +# define WARN_REDEFINE 19 +#endif + +#ifndef WARN_REGEXP +# define WARN_REGEXP 20 +#endif + +#ifndef WARN_SEVERE +# define WARN_SEVERE 21 +#endif + +#ifndef WARN_DEBUGGING +# define WARN_DEBUGGING 22 +#endif + +#ifndef WARN_INPLACE +# define WARN_INPLACE 23 +#endif + +#ifndef WARN_INTERNAL +# define WARN_INTERNAL 24 +#endif + +#ifndef WARN_MALLOC +# define WARN_MALLOC 25 +#endif + +#ifndef WARN_SIGNAL +# define WARN_SIGNAL 26 +#endif + +#ifndef WARN_SUBSTR +# define WARN_SUBSTR 27 +#endif + +#ifndef WARN_SYNTAX +# define WARN_SYNTAX 28 +#endif + +#ifndef WARN_AMBIGUOUS +# define WARN_AMBIGUOUS 29 +#endif + +#ifndef WARN_BAREWORD +# define WARN_BAREWORD 30 +#endif + +#ifndef WARN_DIGIT +# define WARN_DIGIT 31 +#endif + +#ifndef WARN_PARENTHESIS +# define WARN_PARENTHESIS 32 +#endif + +#ifndef WARN_PRECEDENCE +# define WARN_PRECEDENCE 33 +#endif + +#ifndef WARN_PRINTF +# define WARN_PRINTF 34 +#endif + +#ifndef WARN_PROTOTYPE +# define WARN_PROTOTYPE 35 +#endif + +#ifndef WARN_QW +# define WARN_QW 36 +#endif + +#ifndef WARN_RESERVED +# define WARN_RESERVED 37 +#endif + +#ifndef WARN_SEMICOLON +# define WARN_SEMICOLON 38 +#endif + +#ifndef WARN_TAINT +# define WARN_TAINT 39 +#endif + +#ifndef WARN_THREADS +# define WARN_THREADS 40 +#endif + +#ifndef WARN_UNINITIALIZED +# define WARN_UNINITIALIZED 41 +#endif + +#ifndef WARN_UNPACK +# define WARN_UNPACK 42 +#endif + +#ifndef WARN_UNTIE +# define WARN_UNTIE 43 +#endif + +#ifndef WARN_UTF8 +# define WARN_UTF8 44 +#endif + +#ifndef WARN_VOID +# define WARN_VOID 45 +#endif + +#ifndef WARN_ASSERTIONS +# define WARN_ASSERTIONS 46 +#endif +#ifndef packWARN +# define packWARN(a) (a) +#endif + +#ifndef ckWARN +# ifdef G_WARN_ON +# define ckWARN(a) (PL_dowarn & G_WARN_ON) +# else +# define ckWARN(a) PL_dowarn +# endif +#endif + +#if (PERL_BCDVERSION >= 0x5004000) && !defined(warner) +#if defined(NEED_warner) +static void DPPP_(my_warner)(U32 err, const char *pat, ...); +static +#else +extern void DPPP_(my_warner)(U32 err, const char *pat, ...); +#endif + +#define Perl_warner DPPP_(my_warner) + +#if defined(NEED_warner) || defined(NEED_warner_GLOBAL) + +void +DPPP_(my_warner)(U32 err, const char *pat, ...) +{ + SV *sv; + va_list args; + + PERL_UNUSED_ARG(err); + + va_start(args, pat); + sv = vnewSVpvf(pat, &args); + va_end(args); + sv_2mortal(sv); + warn("%s", SvPV_nolen(sv)); +} + +#define warner Perl_warner + +#define Perl_warner_nocontext Perl_warner + +#endif +#endif + +/* concatenating with "" ensures that only literal strings are accepted as argument + * note that STR_WITH_LEN() can't be used as argument to macros or functions that + * under some configurations might be macros + */ +#ifndef STR_WITH_LEN +# define STR_WITH_LEN(s) (s ""), (sizeof(s)-1) +#endif +#ifndef newSVpvs +# define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1) +#endif + +#ifndef newSVpvs_flags +# define newSVpvs_flags(str, flags) newSVpvn_flags(str "", sizeof(str) - 1, flags) +#endif + +#ifndef sv_catpvs +# define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1) +#endif + +#ifndef sv_setpvs +# define sv_setpvs(sv, str) sv_setpvn(sv, str "", sizeof(str) - 1) +#endif + +#ifndef hv_fetchs +# define hv_fetchs(hv, key, lval) hv_fetch(hv, key "", sizeof(key) - 1, lval) +#endif + +#ifndef hv_stores +# define hv_stores(hv, key, val) hv_store(hv, key "", sizeof(key) - 1, val, 0) +#endif +#ifndef gv_fetchpvn_flags +# define gv_fetchpvn_flags(name, len, flags, svt) gv_fetchpv(name, flags, svt) +#endif + +#ifndef gv_fetchpvs +# define gv_fetchpvs(name, flags, svt) gv_fetchpvn_flags(name "", sizeof(name) - 1, flags, svt) +#endif + +#ifndef gv_stashpvs +# define gv_stashpvs(name, flags) gv_stashpvn(name "", sizeof(name) - 1, flags) +#endif +#ifndef SvGETMAGIC +# define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END +#endif +#ifndef PERL_MAGIC_sv +# define PERL_MAGIC_sv '\0' +#endif + +#ifndef PERL_MAGIC_overload +# define PERL_MAGIC_overload 'A' +#endif + +#ifndef PERL_MAGIC_overload_elem +# define PERL_MAGIC_overload_elem 'a' +#endif + +#ifndef PERL_MAGIC_overload_table +# define PERL_MAGIC_overload_table 'c' +#endif + +#ifndef PERL_MAGIC_bm +# define PERL_MAGIC_bm 'B' +#endif + +#ifndef PERL_MAGIC_regdata +# define PERL_MAGIC_regdata 'D' +#endif + +#ifndef PERL_MAGIC_regdatum +# define PERL_MAGIC_regdatum 'd' +#endif + +#ifndef PERL_MAGIC_env +# define PERL_MAGIC_env 'E' +#endif + +#ifndef PERL_MAGIC_envelem +# define PERL_MAGIC_envelem 'e' +#endif + +#ifndef PERL_MAGIC_fm +# define PERL_MAGIC_fm 'f' +#endif + +#ifndef PERL_MAGIC_regex_global +# define PERL_MAGIC_regex_global 'g' +#endif + +#ifndef PERL_MAGIC_isa +# define PERL_MAGIC_isa 'I' +#endif + +#ifndef PERL_MAGIC_isaelem +# define PERL_MAGIC_isaelem 'i' +#endif + +#ifndef PERL_MAGIC_nkeys +# define PERL_MAGIC_nkeys 'k' +#endif + +#ifndef PERL_MAGIC_dbfile +# define PERL_MAGIC_dbfile 'L' +#endif + +#ifndef PERL_MAGIC_dbline +# define PERL_MAGIC_dbline 'l' +#endif + +#ifndef PERL_MAGIC_mutex +# define PERL_MAGIC_mutex 'm' +#endif + +#ifndef PERL_MAGIC_shared +# define PERL_MAGIC_shared 'N' +#endif + +#ifndef PERL_MAGIC_shared_scalar +# define PERL_MAGIC_shared_scalar 'n' +#endif + +#ifndef PERL_MAGIC_collxfrm +# define PERL_MAGIC_collxfrm 'o' +#endif + +#ifndef PERL_MAGIC_tied +# define PERL_MAGIC_tied 'P' +#endif + +#ifndef PERL_MAGIC_tiedelem +# define PERL_MAGIC_tiedelem 'p' +#endif + +#ifndef PERL_MAGIC_tiedscalar +# define PERL_MAGIC_tiedscalar 'q' +#endif + +#ifndef PERL_MAGIC_qr +# define PERL_MAGIC_qr 'r' +#endif + +#ifndef PERL_MAGIC_sig +# define PERL_MAGIC_sig 'S' +#endif + +#ifndef PERL_MAGIC_sigelem +# define PERL_MAGIC_sigelem 's' +#endif + +#ifndef PERL_MAGIC_taint +# define PERL_MAGIC_taint 't' +#endif + +#ifndef PERL_MAGIC_uvar +# define PERL_MAGIC_uvar 'U' +#endif + +#ifndef PERL_MAGIC_uvar_elem +# define PERL_MAGIC_uvar_elem 'u' +#endif + +#ifndef PERL_MAGIC_vstring +# define PERL_MAGIC_vstring 'V' +#endif + +#ifndef PERL_MAGIC_vec +# define PERL_MAGIC_vec 'v' +#endif + +#ifndef PERL_MAGIC_utf8 +# define PERL_MAGIC_utf8 'w' +#endif + +#ifndef PERL_MAGIC_substr +# define PERL_MAGIC_substr 'x' +#endif + +#ifndef PERL_MAGIC_defelem +# define PERL_MAGIC_defelem 'y' +#endif + +#ifndef PERL_MAGIC_glob +# define PERL_MAGIC_glob '*' +#endif + +#ifndef PERL_MAGIC_arylen +# define PERL_MAGIC_arylen '#' +#endif + +#ifndef PERL_MAGIC_pos +# define PERL_MAGIC_pos '.' +#endif + +#ifndef PERL_MAGIC_backref +# define PERL_MAGIC_backref '<' +#endif + +#ifndef PERL_MAGIC_ext +# define PERL_MAGIC_ext '~' +#endif + +/* That's the best we can do... */ +#ifndef sv_catpvn_nomg +# define sv_catpvn_nomg sv_catpvn +#endif + +#ifndef sv_catsv_nomg +# define sv_catsv_nomg sv_catsv +#endif + +#ifndef sv_setsv_nomg +# define sv_setsv_nomg sv_setsv +#endif + +#ifndef sv_pvn_nomg +# define sv_pvn_nomg sv_pvn +#endif + +#ifndef SvIV_nomg +# define SvIV_nomg SvIV +#endif + +#ifndef SvUV_nomg +# define SvUV_nomg SvUV +#endif + +#ifndef sv_catpv_mg +# define sv_catpv_mg(sv, ptr) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_catpv(TeMpSv,ptr); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_catpvn_mg +# define sv_catpvn_mg(sv, ptr, len) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_catpvn(TeMpSv,ptr,len); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_catsv_mg +# define sv_catsv_mg(dsv, ssv) \ + STMT_START { \ + SV *TeMpSv = dsv; \ + sv_catsv(TeMpSv,ssv); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setiv_mg +# define sv_setiv_mg(sv, i) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_setiv(TeMpSv,i); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setnv_mg +# define sv_setnv_mg(sv, num) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_setnv(TeMpSv,num); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setpv_mg +# define sv_setpv_mg(sv, ptr) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_setpv(TeMpSv,ptr); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setpvn_mg +# define sv_setpvn_mg(sv, ptr, len) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_setpvn(TeMpSv,ptr,len); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setsv_mg +# define sv_setsv_mg(dsv, ssv) \ + STMT_START { \ + SV *TeMpSv = dsv; \ + sv_setsv(TeMpSv,ssv); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_setuv_mg +# define sv_setuv_mg(sv, i) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_setuv(TeMpSv,i); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif + +#ifndef sv_usepvn_mg +# define sv_usepvn_mg(sv, ptr, len) \ + STMT_START { \ + SV *TeMpSv = sv; \ + sv_usepvn(TeMpSv,ptr,len); \ + SvSETMAGIC(TeMpSv); \ + } STMT_END +#endif +#ifndef SvVSTRING_mg +# define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL) +#endif + +/* Hint: sv_magic_portable + * This is a compatibility function that is only available with + * Devel::PPPort. It is NOT in the perl core. + * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when + * it is being passed a name pointer with namlen == 0. In that + * case, perl 5.8.0 and later store the pointer, not a copy of it. + * The compatibility can be provided back to perl 5.004. With + * earlier versions, the code will not compile. + */ + +#if (PERL_BCDVERSION < 0x5004000) + + /* code that uses sv_magic_portable will not compile */ + +#elif (PERL_BCDVERSION < 0x5008000) + +# define sv_magic_portable(sv, obj, how, name, namlen) \ + STMT_START { \ + SV *SvMp_sv = (sv); \ + char *SvMp_name = (char *) (name); \ + I32 SvMp_namlen = (namlen); \ + if (SvMp_name && SvMp_namlen == 0) \ + { \ + MAGIC *mg; \ + sv_magic(SvMp_sv, obj, how, 0, 0); \ + mg = SvMAGIC(SvMp_sv); \ + mg->mg_len = -42; /* XXX: this is the tricky part */ \ + mg->mg_ptr = SvMp_name; \ + } \ + else \ + { \ + sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \ + } \ + } STMT_END + +#else + +# define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e) + +#endif + +#ifdef USE_ITHREADS +#ifndef CopFILE +# define CopFILE(c) ((c)->cop_file) +#endif + +#ifndef CopFILEGV +# define CopFILEGV(c) (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv) +#endif + +#ifndef CopFILE_set +# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) +#endif + +#ifndef CopFILESV +# define CopFILESV(c) (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv) +#endif + +#ifndef CopFILEAV +# define CopFILEAV(c) (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav) +#endif + +#ifndef CopSTASHPV +# define CopSTASHPV(c) ((c)->cop_stashpv) +#endif + +#ifndef CopSTASHPV_set +# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) +#endif + +#ifndef CopSTASH +# define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv) +#endif + +#ifndef CopSTASH_set +# define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch) +#endif + +#ifndef CopSTASH_eq +# define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \ + || (CopSTASHPV(c) && HvNAME(hv) \ + && strEQ(CopSTASHPV(c), HvNAME(hv))))) +#endif + +#else +#ifndef CopFILEGV +# define CopFILEGV(c) ((c)->cop_filegv) +#endif + +#ifndef CopFILEGV_set +# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv)) +#endif + +#ifndef CopFILE_set +# define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv)) +#endif + +#ifndef CopFILESV +# define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv) +#endif + +#ifndef CopFILEAV +# define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav) +#endif + +#ifndef CopFILE +# define CopFILE(c) (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch) +#endif + +#ifndef CopSTASH +# define CopSTASH(c) ((c)->cop_stash) +#endif + +#ifndef CopSTASH_set +# define CopSTASH_set(c,hv) ((c)->cop_stash = (hv)) +#endif + +#ifndef CopSTASHPV +# define CopSTASHPV(c) (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch) +#endif + +#ifndef CopSTASHPV_set +# define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD)) +#endif + +#ifndef CopSTASH_eq +# define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv)) +#endif + +#endif /* USE_ITHREADS */ +#ifndef IN_PERL_COMPILETIME +# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) +#endif + +#ifndef IN_LOCALE_RUNTIME +# define IN_LOCALE_RUNTIME (PL_curcop->op_private & HINT_LOCALE) +#endif + +#ifndef IN_LOCALE_COMPILETIME +# define IN_LOCALE_COMPILETIME (PL_hints & HINT_LOCALE) +#endif + +#ifndef IN_LOCALE +# define IN_LOCALE (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME) +#endif +#ifndef IS_NUMBER_IN_UV +# define IS_NUMBER_IN_UV 0x01 +#endif + +#ifndef IS_NUMBER_GREATER_THAN_UV_MAX +# define IS_NUMBER_GREATER_THAN_UV_MAX 0x02 +#endif + +#ifndef IS_NUMBER_NOT_INT +# define IS_NUMBER_NOT_INT 0x04 +#endif + +#ifndef IS_NUMBER_NEG +# define IS_NUMBER_NEG 0x08 +#endif + +#ifndef IS_NUMBER_INFINITY +# define IS_NUMBER_INFINITY 0x10 +#endif + +#ifndef IS_NUMBER_NAN +# define IS_NUMBER_NAN 0x20 +#endif +#ifndef GROK_NUMERIC_RADIX +# define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send) +#endif +#ifndef PERL_SCAN_GREATER_THAN_UV_MAX +# define PERL_SCAN_GREATER_THAN_UV_MAX 0x02 +#endif + +#ifndef PERL_SCAN_SILENT_ILLDIGIT +# define PERL_SCAN_SILENT_ILLDIGIT 0x04 +#endif + +#ifndef PERL_SCAN_ALLOW_UNDERSCORES +# define PERL_SCAN_ALLOW_UNDERSCORES 0x01 +#endif + +#ifndef PERL_SCAN_DISALLOW_PREFIX +# define PERL_SCAN_DISALLOW_PREFIX 0x02 +#endif + +#ifndef grok_numeric_radix +#if defined(NEED_grok_numeric_radix) +static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); +static +#else +extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); +#endif + +#ifdef grok_numeric_radix +# undef grok_numeric_radix +#endif +#define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b) +#define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix) + +#if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL) +bool +DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send) +{ +#ifdef USE_LOCALE_NUMERIC +#ifdef PL_numeric_radix_sv + if (PL_numeric_radix_sv && IN_LOCALE) { + STRLEN len; + char* radix = SvPV(PL_numeric_radix_sv, len); + if (*sp + len <= send && memEQ(*sp, radix, len)) { + *sp += len; + return TRUE; + } + } +#else + /* older perls don't have PL_numeric_radix_sv so the radix + * must manually be requested from locale.h + */ +#include + dTHR; /* needed for older threaded perls */ + struct lconv *lc = localeconv(); + char *radix = lc->decimal_point; + if (radix && IN_LOCALE) { + STRLEN len = strlen(radix); + if (*sp + len <= send && memEQ(*sp, radix, len)) { + *sp += len; + return TRUE; + } + } +#endif +#endif /* USE_LOCALE_NUMERIC */ + /* always try "." if numeric radix didn't match because + * we may have data from different locales mixed */ + if (*sp < send && **sp == '.') { + ++*sp; + return TRUE; + } + return FALSE; +} +#endif +#endif + +#ifndef grok_number +#if defined(NEED_grok_number) +static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); +static +#else +extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); +#endif + +#ifdef grok_number +# undef grok_number +#endif +#define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c) +#define Perl_grok_number DPPP_(my_grok_number) + +#if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL) +int +DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep) +{ + const char *s = pv; + const char *send = pv + len; + const UV max_div_10 = UV_MAX / 10; + const char max_mod_10 = UV_MAX % 10; + int numtype = 0; + int sawinf = 0; + int sawnan = 0; + + while (s < send && isSPACE(*s)) + s++; + if (s == send) { + return 0; + } else if (*s == '-') { + s++; + numtype = IS_NUMBER_NEG; + } + else if (*s == '+') + s++; + + if (s == send) + return 0; + + /* next must be digit or the radix separator or beginning of infinity */ + if (isDIGIT(*s)) { + /* UVs are at least 32 bits, so the first 9 decimal digits cannot + overflow. */ + UV value = *s - '0'; + /* This construction seems to be more optimiser friendly. + (without it gcc does the isDIGIT test and the *s - '0' separately) + With it gcc on arm is managing 6 instructions (6 cycles) per digit. + In theory the optimiser could deduce how far to unroll the loop + before checking for overflow. */ + if (++s < send) { + int digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + digit = *s - '0'; + if (digit >= 0 && digit <= 9) { + value = value * 10 + digit; + if (++s < send) { + /* Now got 9 digits, so need to check + each time for overflow. */ + digit = *s - '0'; + while (digit >= 0 && digit <= 9 + && (value < max_div_10 + || (value == max_div_10 + && digit <= max_mod_10))) { + value = value * 10 + digit; + if (++s < send) + digit = *s - '0'; + else + break; + } + if (digit >= 0 && digit <= 9 + && (s < send)) { + /* value overflowed. + skip the remaining digits, don't + worry about setting *valuep. */ + do { + s++; + } while (s < send && isDIGIT(*s)); + numtype |= + IS_NUMBER_GREATER_THAN_UV_MAX; + goto skip_value; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + numtype |= IS_NUMBER_IN_UV; + if (valuep) + *valuep = value; + + skip_value: + if (GROK_NUMERIC_RADIX(&s, send)) { + numtype |= IS_NUMBER_NOT_INT; + while (s < send && isDIGIT(*s)) /* optional digits after the radix */ + s++; + } + } + else if (GROK_NUMERIC_RADIX(&s, send)) { + numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */ + /* no digits before the radix means we need digits after it */ + if (s < send && isDIGIT(*s)) { + do { + s++; + } while (s < send && isDIGIT(*s)); + if (valuep) { + /* integer approximation is valid - it's 0. */ + *valuep = 0; + } + } + else + return 0; + } else if (*s == 'I' || *s == 'i') { + s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; + s++; if (s == send || (*s != 'F' && *s != 'f')) return 0; + s++; if (s < send && (*s == 'I' || *s == 'i')) { + s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; + s++; if (s == send || (*s != 'I' && *s != 'i')) return 0; + s++; if (s == send || (*s != 'T' && *s != 't')) return 0; + s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0; + s++; + } + sawinf = 1; + } else if (*s == 'N' || *s == 'n') { + /* XXX TODO: There are signaling NaNs and quiet NaNs. */ + s++; if (s == send || (*s != 'A' && *s != 'a')) return 0; + s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; + s++; + sawnan = 1; + } else + return 0; + + if (sawinf) { + numtype &= IS_NUMBER_NEG; /* Keep track of sign */ + numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT; + } else if (sawnan) { + numtype &= IS_NUMBER_NEG; /* Keep track of sign */ + numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT; + } else if (s < send) { + /* we can have an optional exponent part */ + if (*s == 'e' || *s == 'E') { + /* The only flag we keep is sign. Blow away any "it's UV" */ + numtype &= IS_NUMBER_NEG; + numtype |= IS_NUMBER_NOT_INT; + s++; + if (s < send && (*s == '-' || *s == '+')) + s++; + if (s < send && isDIGIT(*s)) { + do { + s++; + } while (s < send && isDIGIT(*s)); + } + else + return 0; + } + } + while (s < send && isSPACE(*s)) + s++; + if (s >= send) + return numtype; + if (len == 10 && memEQ(pv, "0 but true", 10)) { + if (valuep) + *valuep = 0; + return IS_NUMBER_IN_UV; + } + return 0; +} +#endif +#endif + +/* + * The grok_* routines have been modified to use warn() instead of + * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit, + * which is why the stack variable has been renamed to 'xdigit'. + */ + +#ifndef grok_bin +#if defined(NEED_grok_bin) +static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +static +#else +extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +#endif + +#ifdef grok_bin +# undef grok_bin +#endif +#define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d) +#define Perl_grok_bin DPPP_(my_grok_bin) + +#if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL) +UV +DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) +{ + const char *s = start; + STRLEN len = *len_p; + UV value = 0; + NV value_nv = 0; + + const UV max_div_2 = UV_MAX / 2; + bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; + bool overflowed = FALSE; + + if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { + /* strip off leading b or 0b. + for compatibility silently suffer "b" and "0b" as valid binary + numbers. */ + if (len >= 1) { + if (s[0] == 'b') { + s++; + len--; + } + else if (len >= 2 && s[0] == '0' && s[1] == 'b') { + s+=2; + len-=2; + } + } + } + + for (; len-- && *s; s++) { + char bit = *s; + if (bit == '0' || bit == '1') { + /* Write it in this wonky order with a goto to attempt to get the + compiler to make the common case integer-only loop pretty tight. + With gcc seems to be much straighter code than old scan_bin. */ + redo: + if (!overflowed) { + if (value <= max_div_2) { + value = (value << 1) | (bit - '0'); + continue; + } + /* Bah. We're just overflowed. */ + warn("Integer overflow in binary number"); + overflowed = TRUE; + value_nv = (NV) value; + } + value_nv *= 2.0; + /* If an NV has not enough bits in its mantissa to + * represent a UV this summing of small low-order numbers + * is a waste of time (because the NV cannot preserve + * the low-order bits anyway): we could just remember when + * did we overflow and in the end just multiply value_nv by the + * right amount. */ + value_nv += (NV)(bit - '0'); + continue; + } + if (bit == '_' && len && allow_underscores && (bit = s[1]) + && (bit == '0' || bit == '1')) + { + --len; + ++s; + goto redo; + } + if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) + warn("Illegal binary digit '%c' ignored", *s); + break; + } + + if ( ( overflowed && value_nv > 4294967295.0) +#if UVSIZE > 4 + || (!overflowed && value > 0xffffffff ) +#endif + ) { + warn("Binary number > 0b11111111111111111111111111111111 non-portable"); + } + *len_p = s - start; + if (!overflowed) { + *flags = 0; + return value; + } + *flags = PERL_SCAN_GREATER_THAN_UV_MAX; + if (result) + *result = value_nv; + return UV_MAX; +} +#endif +#endif + +#ifndef grok_hex +#if defined(NEED_grok_hex) +static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +static +#else +extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +#endif + +#ifdef grok_hex +# undef grok_hex +#endif +#define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d) +#define Perl_grok_hex DPPP_(my_grok_hex) + +#if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL) +UV +DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) +{ + const char *s = start; + STRLEN len = *len_p; + UV value = 0; + NV value_nv = 0; + + const UV max_div_16 = UV_MAX / 16; + bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; + bool overflowed = FALSE; + const char *xdigit; + + if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { + /* strip off leading x or 0x. + for compatibility silently suffer "x" and "0x" as valid hex numbers. + */ + if (len >= 1) { + if (s[0] == 'x') { + s++; + len--; + } + else if (len >= 2 && s[0] == '0' && s[1] == 'x') { + s+=2; + len-=2; + } + } + } + + for (; len-- && *s; s++) { + xdigit = strchr((char *) PL_hexdigit, *s); + if (xdigit) { + /* Write it in this wonky order with a goto to attempt to get the + compiler to make the common case integer-only loop pretty tight. + With gcc seems to be much straighter code than old scan_hex. */ + redo: + if (!overflowed) { + if (value <= max_div_16) { + value = (value << 4) | ((xdigit - PL_hexdigit) & 15); + continue; + } + warn("Integer overflow in hexadecimal number"); + overflowed = TRUE; + value_nv = (NV) value; + } + value_nv *= 16.0; + /* If an NV has not enough bits in its mantissa to + * represent a UV this summing of small low-order numbers + * is a waste of time (because the NV cannot preserve + * the low-order bits anyway): we could just remember when + * did we overflow and in the end just multiply value_nv by the + * right amount of 16-tuples. */ + value_nv += (NV)((xdigit - PL_hexdigit) & 15); + continue; + } + if (*s == '_' && len && allow_underscores && s[1] + && (xdigit = strchr((char *) PL_hexdigit, s[1]))) + { + --len; + ++s; + goto redo; + } + if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) + warn("Illegal hexadecimal digit '%c' ignored", *s); + break; + } + + if ( ( overflowed && value_nv > 4294967295.0) +#if UVSIZE > 4 + || (!overflowed && value > 0xffffffff ) +#endif + ) { + warn("Hexadecimal number > 0xffffffff non-portable"); + } + *len_p = s - start; + if (!overflowed) { + *flags = 0; + return value; + } + *flags = PERL_SCAN_GREATER_THAN_UV_MAX; + if (result) + *result = value_nv; + return UV_MAX; +} +#endif +#endif + +#ifndef grok_oct +#if defined(NEED_grok_oct) +static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +static +#else +extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); +#endif + +#ifdef grok_oct +# undef grok_oct +#endif +#define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d) +#define Perl_grok_oct DPPP_(my_grok_oct) + +#if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL) +UV +DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) +{ + const char *s = start; + STRLEN len = *len_p; + UV value = 0; + NV value_nv = 0; + + const UV max_div_8 = UV_MAX / 8; + bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; + bool overflowed = FALSE; + + for (; len-- && *s; s++) { + /* gcc 2.95 optimiser not smart enough to figure that this subtraction + out front allows slicker code. */ + int digit = *s - '0'; + if (digit >= 0 && digit <= 7) { + /* Write it in this wonky order with a goto to attempt to get the + compiler to make the common case integer-only loop pretty tight. + */ + redo: + if (!overflowed) { + if (value <= max_div_8) { + value = (value << 3) | digit; + continue; + } + /* Bah. We're just overflowed. */ + warn("Integer overflow in octal number"); + overflowed = TRUE; + value_nv = (NV) value; + } + value_nv *= 8.0; + /* If an NV has not enough bits in its mantissa to + * represent a UV this summing of small low-order numbers + * is a waste of time (because the NV cannot preserve + * the low-order bits anyway): we could just remember when + * did we overflow and in the end just multiply value_nv by the + * right amount of 8-tuples. */ + value_nv += (NV)digit; + continue; + } + if (digit == ('_' - '0') && len && allow_underscores + && (digit = s[1] - '0') && (digit >= 0 && digit <= 7)) + { + --len; + ++s; + goto redo; + } + /* Allow \octal to work the DWIM way (that is, stop scanning + * as soon as non-octal characters are seen, complain only iff + * someone seems to want to use the digits eight and nine). */ + if (digit == 8 || digit == 9) { + if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) + warn("Illegal octal digit '%c' ignored", *s); + } + break; + } + + if ( ( overflowed && value_nv > 4294967295.0) +#if UVSIZE > 4 + || (!overflowed && value > 0xffffffff ) +#endif + ) { + warn("Octal number > 037777777777 non-portable"); + } + *len_p = s - start; + if (!overflowed) { + *flags = 0; + return value; + } + *flags = PERL_SCAN_GREATER_THAN_UV_MAX; + if (result) + *result = value_nv; + return UV_MAX; +} +#endif +#endif + +#if !defined(my_snprintf) +#if defined(NEED_my_snprintf) +static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); +static +#else +extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); +#endif + +#define my_snprintf DPPP_(my_my_snprintf) +#define Perl_my_snprintf DPPP_(my_my_snprintf) + +#if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL) + +int +DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...) +{ + dTHX; + int retval; + va_list ap; + va_start(ap, format); +#ifdef HAS_VSNPRINTF + retval = vsnprintf(buffer, len, format, ap); +#else + retval = vsprintf(buffer, format, ap); +#endif + va_end(ap); + if (retval < 0 || (len > 0 && (Size_t)retval >= len)) + Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); + return retval; +} + +#endif +#endif + +#if !defined(my_sprintf) +#if defined(NEED_my_sprintf) +static int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); +static +#else +extern int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); +#endif + +#define my_sprintf DPPP_(my_my_sprintf) +#define Perl_my_sprintf DPPP_(my_my_sprintf) + +#if defined(NEED_my_sprintf) || defined(NEED_my_sprintf_GLOBAL) + +int +DPPP_(my_my_sprintf)(char *buffer, const char* pat, ...) +{ + va_list args; + va_start(args, pat); + vsprintf(buffer, pat, args); + va_end(args); + return strlen(buffer); +} + +#endif +#endif + +#ifdef NO_XSLOCKS +# ifdef dJMPENV +# define dXCPT dJMPENV; int rEtV = 0 +# define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0) +# define XCPT_TRY_END JMPENV_POP; +# define XCPT_CATCH if (rEtV != 0) +# define XCPT_RETHROW JMPENV_JUMP(rEtV) +# else +# define dXCPT Sigjmp_buf oldTOP; int rEtV = 0 +# define XCPT_TRY_START Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0) +# define XCPT_TRY_END Copy(oldTOP, top_env, 1, Sigjmp_buf); +# define XCPT_CATCH if (rEtV != 0) +# define XCPT_RETHROW Siglongjmp(top_env, rEtV) +# endif +#endif + +#if !defined(my_strlcat) +#if defined(NEED_my_strlcat) +static Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); +static +#else +extern Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); +#endif + +#define my_strlcat DPPP_(my_my_strlcat) +#define Perl_my_strlcat DPPP_(my_my_strlcat) + +#if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL) + +Size_t +DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size) +{ + Size_t used, length, copy; + + used = strlen(dst); + length = strlen(src); + if (size > 0 && used < size - 1) { + copy = (length >= size - used) ? size - used - 1 : length; + memcpy(dst + used, src, copy); + dst[used + copy] = '\0'; + } + return used + length; +} +#endif +#endif + +#if !defined(my_strlcpy) +#if defined(NEED_my_strlcpy) +static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); +static +#else +extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); +#endif + +#define my_strlcpy DPPP_(my_my_strlcpy) +#define Perl_my_strlcpy DPPP_(my_my_strlcpy) + +#if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL) + +Size_t +DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size) +{ + Size_t length, copy; + + length = strlen(src); + if (size > 0) { + copy = (length >= size) ? size - 1 : length; + memcpy(dst, src, copy); + dst[copy] = '\0'; + } + return length; +} + +#endif +#endif +#ifndef PERL_PV_ESCAPE_QUOTE +# define PERL_PV_ESCAPE_QUOTE 0x0001 +#endif + +#ifndef PERL_PV_PRETTY_QUOTE +# define PERL_PV_PRETTY_QUOTE PERL_PV_ESCAPE_QUOTE +#endif + +#ifndef PERL_PV_PRETTY_ELLIPSES +# define PERL_PV_PRETTY_ELLIPSES 0x0002 +#endif + +#ifndef PERL_PV_PRETTY_LTGT +# define PERL_PV_PRETTY_LTGT 0x0004 +#endif + +#ifndef PERL_PV_ESCAPE_FIRSTCHAR +# define PERL_PV_ESCAPE_FIRSTCHAR 0x0008 +#endif + +#ifndef PERL_PV_ESCAPE_UNI +# define PERL_PV_ESCAPE_UNI 0x0100 +#endif + +#ifndef PERL_PV_ESCAPE_UNI_DETECT +# define PERL_PV_ESCAPE_UNI_DETECT 0x0200 +#endif + +#ifndef PERL_PV_ESCAPE_ALL +# define PERL_PV_ESCAPE_ALL 0x1000 +#endif + +#ifndef PERL_PV_ESCAPE_NOBACKSLASH +# define PERL_PV_ESCAPE_NOBACKSLASH 0x2000 +#endif + +#ifndef PERL_PV_ESCAPE_NOCLEAR +# define PERL_PV_ESCAPE_NOCLEAR 0x4000 +#endif + +#ifndef PERL_PV_ESCAPE_RE +# define PERL_PV_ESCAPE_RE 0x8000 +#endif + +#ifndef PERL_PV_PRETTY_NOCLEAR +# define PERL_PV_PRETTY_NOCLEAR PERL_PV_ESCAPE_NOCLEAR +#endif +#ifndef PERL_PV_PRETTY_DUMP +# define PERL_PV_PRETTY_DUMP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_QUOTE +#endif + +#ifndef PERL_PV_PRETTY_REGPROP +# define PERL_PV_PRETTY_REGPROP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_LTGT|PERL_PV_ESCAPE_RE +#endif + +/* Hint: pv_escape + * Note that unicode functionality is only backported to + * those perl versions that support it. For older perl + * versions, the implementation will fall back to bytes. + */ + +#ifndef pv_escape +#if defined(NEED_pv_escape) +static char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); +static +#else +extern char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); +#endif + +#ifdef pv_escape +# undef pv_escape +#endif +#define pv_escape(a,b,c,d,e,f) DPPP_(my_pv_escape)(aTHX_ a,b,c,d,e,f) +#define Perl_pv_escape DPPP_(my_pv_escape) + +#if defined(NEED_pv_escape) || defined(NEED_pv_escape_GLOBAL) + +char * +DPPP_(my_pv_escape)(pTHX_ SV *dsv, char const * const str, + const STRLEN count, const STRLEN max, + STRLEN * const escaped, const U32 flags) +{ + const char esc = flags & PERL_PV_ESCAPE_RE ? '%' : '\\'; + const char dq = flags & PERL_PV_ESCAPE_QUOTE ? '"' : esc; + char octbuf[32] = "%123456789ABCDF"; + STRLEN wrote = 0; + STRLEN chsize = 0; + STRLEN readsize = 1; +#if defined(is_utf8_string) && defined(utf8_to_uvchr) + bool isuni = flags & PERL_PV_ESCAPE_UNI ? 1 : 0; +#endif + const char *pv = str; + const char * const end = pv + count; + octbuf[0] = esc; + + if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) + sv_setpvs(dsv, ""); + +#if defined(is_utf8_string) && defined(utf8_to_uvchr) + if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count)) + isuni = 1; +#endif + + for (; pv < end && (!max || wrote < max) ; pv += readsize) { + const UV u = +#if defined(is_utf8_string) && defined(utf8_to_uvchr) + isuni ? utf8_to_uvchr((U8*)pv, &readsize) : +#endif + (U8)*pv; + const U8 c = (U8)u & 0xFF; + + if (u > 255 || (flags & PERL_PV_ESCAPE_ALL)) { + if (flags & PERL_PV_ESCAPE_FIRSTCHAR) + chsize = my_snprintf(octbuf, sizeof octbuf, + "%"UVxf, u); + else + chsize = my_snprintf(octbuf, sizeof octbuf, + "%cx{%"UVxf"}", esc, u); + } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) { + chsize = 1; + } else { + if (c == dq || c == esc || !isPRINT(c)) { + chsize = 2; + switch (c) { + case '\\' : /* fallthrough */ + case '%' : if (c == esc) + octbuf[1] = esc; + else + chsize = 1; + break; + case '\v' : octbuf[1] = 'v'; break; + case '\t' : octbuf[1] = 't'; break; + case '\r' : octbuf[1] = 'r'; break; + case '\n' : octbuf[1] = 'n'; break; + case '\f' : octbuf[1] = 'f'; break; + case '"' : if (dq == '"') + octbuf[1] = '"'; + else + chsize = 1; + break; + default: chsize = my_snprintf(octbuf, sizeof octbuf, + pv < end && isDIGIT((U8)*(pv+readsize)) + ? "%c%03o" : "%c%o", esc, c); + } + } else { + chsize = 1; + } + } + if (max && wrote + chsize > max) { + break; + } else if (chsize > 1) { + sv_catpvn(dsv, octbuf, chsize); + wrote += chsize; + } else { + char tmp[2]; + my_snprintf(tmp, sizeof tmp, "%c", c); + sv_catpvn(dsv, tmp, 1); + wrote++; + } + if (flags & PERL_PV_ESCAPE_FIRSTCHAR) + break; + } + if (escaped != NULL) + *escaped= pv - str; + return SvPVX(dsv); +} + +#endif +#endif + +#ifndef pv_pretty +#if defined(NEED_pv_pretty) +static char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); +static +#else +extern char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); +#endif + +#ifdef pv_pretty +# undef pv_pretty +#endif +#define pv_pretty(a,b,c,d,e,f,g) DPPP_(my_pv_pretty)(aTHX_ a,b,c,d,e,f,g) +#define Perl_pv_pretty DPPP_(my_pv_pretty) + +#if defined(NEED_pv_pretty) || defined(NEED_pv_pretty_GLOBAL) + +char * +DPPP_(my_pv_pretty)(pTHX_ SV *dsv, char const * const str, const STRLEN count, + const STRLEN max, char const * const start_color, char const * const end_color, + const U32 flags) +{ + const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%'; + STRLEN escaped; + + if (!(flags & PERL_PV_PRETTY_NOCLEAR)) + sv_setpvs(dsv, ""); + + if (dq == '"') + sv_catpvs(dsv, "\""); + else if (flags & PERL_PV_PRETTY_LTGT) + sv_catpvs(dsv, "<"); + + if (start_color != NULL) + sv_catpv(dsv, D_PPP_CONSTPV_ARG(start_color)); + + pv_escape(dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR); + + if (end_color != NULL) + sv_catpv(dsv, D_PPP_CONSTPV_ARG(end_color)); + + if (dq == '"') + sv_catpvs(dsv, "\""); + else if (flags & PERL_PV_PRETTY_LTGT) + sv_catpvs(dsv, ">"); + + if ((flags & PERL_PV_PRETTY_ELLIPSES) && escaped < count) + sv_catpvs(dsv, "..."); + + return SvPVX(dsv); +} + +#endif +#endif + +#ifndef pv_display +#if defined(NEED_pv_display) +static char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); +static +#else +extern char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); +#endif + +#ifdef pv_display +# undef pv_display +#endif +#define pv_display(a,b,c,d,e) DPPP_(my_pv_display)(aTHX_ a,b,c,d,e) +#define Perl_pv_display DPPP_(my_pv_display) + +#if defined(NEED_pv_display) || defined(NEED_pv_display_GLOBAL) + +char * +DPPP_(my_pv_display)(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim) +{ + pv_pretty(dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP); + if (len > cur && pv[cur] == '\0') + sv_catpvs(dsv, "\\0"); + return SvPVX(dsv); +} + +#endif +#endif + +#endif /* _P_P_PORTABILITY_H_ */ + +/* End of File ppport.h */ diff --git a/kvperl/t/KVSpool.t b/kvperl/t/KVSpool.t new file mode 100644 index 0000000..d4d856e --- /dev/null +++ b/kvperl/t/KVSpool.t @@ -0,0 +1,30 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl KVSpool.t' + +######################### + +# change 'tests => 2' to 'tests => last_test_to_print'; + +use Test::More tests => 2; +BEGIN { use_ok('KVSpool') }; + + +my $fail = 0; +foreach my $constname (qw( + KV_BASE_MAX)) { + next if (eval "my \$a = $constname; 1"); + if ($@ =~ /^Your vendor has not defined KVSpool macro $constname/) { + print "# pass: $@"; + } else { + print "# fail: $@"; + $fail = 1; + } + +} + +ok( $fail == 0 , 'Constants' ); +######################### + +# Insert your test code below, the Test::More module is use()ed here so read +# its man page ( perldoc Test::More ) for help writing this test script. + diff --git a/kvperl/test.pl b/kvperl/test.pl new file mode 100644 index 0000000..d07df3a --- /dev/null +++ b/kvperl/test.pl @@ -0,0 +1,34 @@ +use KVSpool; +use Data::Dumper; +use Text::CSV; +use Text::CSV_XS; + +#my $hh = KVSpool::read("/home/adamstr1/cic/spool","",1); +my $v = KVSpool->new("/home/adamstr1/cic/spool","spoo"); + + +my $csv = Text::CSV->new({always_quote => 1}); + +#open FILE, ">", "text.csv"; +@cols = ('keyval'); +sub hashtoaref { + my $hash = shift; + my @columns = shift; + my @arry; + foreach my $col (@columns) { + push(@arry,$hash->{$col}); + } + return \@arry; +} + +#$status = $csv->print(\*FILE,$colref); +#print Dumper $v->read(1); +#print Dumper $v->read(); +#print Dumper $v->stat(); + + + +my $h = {'keyval'=>'dude'}; +print Dumper hashtoaref($h,@cols); +#$v->write($h); +print "foo"; diff --git a/kvpy/Makefile b/kvpy/Makefile new file mode 100644 index 0000000..fb52f5b --- /dev/null +++ b/kvpy/Makefile @@ -0,0 +1,16 @@ +all: kvpy + +kvpy: kvpymodule.c ../libkvspool.a + rm -rf build + python build.py build + +install: + @echo "Installing (typically in /usr/local/lib/python2.6/dist-packages/)" + python build.py install + +.PHONY: clean distclean +clean: + @python build.py $@ + rm -rf build + +distclean: clean diff --git a/kvpy/build.py b/kvpy/build.py new file mode 100644 index 0000000..43d58a8 --- /dev/null +++ b/kvpy/build.py @@ -0,0 +1,12 @@ +from distutils.core import setup, Extension + +module1 = Extension('kvpy', + sources = ['kvpymodule.c'], + include_dirs=['../'], + library_dirs = ['../'], + libraries = ['kvspool']) + +setup (name = 'KvPyModule', + version = '1.0', + description = 'Python interface to kvspool', + ext_modules = [module1]) diff --git a/kvpy/kvpymodule.c b/kvpy/kvpymodule.c new file mode 100644 index 0000000..0ea6dea --- /dev/null +++ b/kvpy/kvpymodule.c @@ -0,0 +1,202 @@ +/* kvpy.c - by Troy Hanson + */ + +#include "Python.h" +#include "kvspool.h" + +static int dictionary_to_kvs(PyObject *dict, void *set) { + PyObject *pk, *pv; + int rc = -1; + //Py_ssize_t pos = 0; + /* Python 2.4 lacked Py_ssize_t */ + ssize_t pos = 0; + char *k, *v; + + while (PyDict_Next(dict, &pos, &pk, &pv)) { + k = PyString_AsString(pk); + v = PyString_AsString(pv); + if (!k || !v) goto done; + kv_adds(set, k, v); + } + rc = 0; + done: + return rc; +} + +static int kvs_to_dictionary(PyObject **_dict, void *set) { + PyObject *pk, *pv; + int rc = -1; + + PyObject *dict = PyDict_New(); + + kv_t *kv=NULL; + while ( (kv= kv_next(set,kv))) { + + pk = Py_BuildValue("s#",kv->key,(int)kv->klen); + switch(kv->fmt) { + case 'c': pv = Py_BuildValue("b",*(char*)kv->val); break; + case 'm': pv = Py_BuildValue("h",*( int16_t*)kv->val); break; + case 'n': pv = Py_BuildValue("H",*(uint16_t*)kv->val); break; + case 'd': pv = Py_BuildValue("i",*( int32_t*)kv->val); break; + case 'u': pv = Py_BuildValue("I",*(uint32_t*)kv->val); break; + case 'D': pv = Py_BuildValue("l",*( int64_t*)kv->val); break; + case 'U': pv = Py_BuildValue("L",*(uint64_t*)kv->val); break; + case 'b': pv = Py_BuildValue("z#",kv->val,(int)kv->vlen); break; + case 's': pv = Py_BuildValue("s#",kv->val,(int)kv->vlen); break; + case 'f': pv = Py_BuildValue("d",*(double*)kv->val); break; + default: + PyErr_SetString(PyExc_RuntimeError, "unsupported type in spool"); + rc = -1; + goto done; + } + rc = PyDict_SetItem(dict,pk,pv); + Py_DECREF(pk); Py_DECREF(pv); + if (rc == -1) break; + } + + done: + if (rc == -1) { + Py_DECREF(dict); + dict = NULL; + } + *_dict = dict; + return rc; +} + + +static PyObject *kvpy_read(PyObject *self, PyObject *args) +{ + char *dir, *base; + int block, rc; + void *sp, *set; + PyObject *dict = NULL; + + if (!PyArg_ParseTuple(args, "ssi:kvpy_read", &dir, &base, &block)) { + return NULL; + } + + /* normalize inputs */ + if (*base == '\0') base=NULL; + block = block ? 1 : 0; + + /* try to read a spool frame */ + if ( (sp = kv_spoolreader_new(dir,base)) == NULL) { + PyErr_SetString(PyExc_RuntimeError, "cannot initialize spool reader"); + return NULL; + } + + set = kv_set_new(); + if ( (rc=kv_spool_read(sp,set,block)) > 0) { + kvs_to_dictionary(&dict, set); + } else if (rc == 0) { + PyErr_SetString(PyExc_RuntimeError, "no frames available"); + } else if (rc < 0) { + PyErr_SetString(PyExc_RuntimeError, "internal error in spool reader"); + } + + kv_set_free(set); + kv_spoolreader_free(sp); + return dict; +} + +static PyObject *kvpy_write(PyObject *self, PyObject *args) +{ + char *dir, *base; + void *sp, *set; + PyObject *dict; + + if (!PyArg_ParseTuple(args, "ssO:kvpy_write", &dir, &base, &dict)) { + return NULL; + } + + /* normalize inputs */ + if (*base == '\0') { + PyErr_SetString(PyExc_RuntimeError, "base cannot be empty"); + return NULL; + } + + /* try to write a spool frame */ + if ( (sp = kv_spoolwriter_new(dir,base)) == NULL) { + PyErr_SetString(PyExc_RuntimeError, "cannot initialize spool writer"); + return NULL; + } + + set = kv_set_new(); + if (dictionary_to_kvs(dict, set) == -1) { + PyErr_SetString(PyExc_RuntimeError, "non-string key or value"); + return NULL; + } + kv_spool_write(sp,set); + kv_set_free(set); + kv_spoolwriter_free(sp); + return Py_BuildValue("i", 1); +} + +static PyObject *kvpy_stat(PyObject *self, PyObject *args) +{ + char *dir, *base; + int rc=0, sc, i; + kv_stat_t *stats; + PyObject *dict = NULL; + PyObject *pk, *pv; + + if (!PyArg_ParseTuple(args, "ss:kvpy_read", &dir, &base)) { + return NULL; + } + + if (*base == '\0') base=NULL; + + sc = kv_stat(dir,base,&stats); + if (sc == -1) { + PyErr_SetString(PyExc_RuntimeError, "kv_stat failed"); + return NULL; + } + + dict = PyDict_New(); + for(i=0; i < sc; i++) { + pk = PyString_FromString(stats[i].base); + pv = PyInt_FromLong((long)(stats[i].pct_consumed)); + rc = PyDict_SetItem(dict,pk,pv); + Py_DECREF(pk); + Py_DECREF(pv); + if (rc == -1) break; + } + if (stats) free(stats); + if (rc == -1) { + Py_DECREF(dict); + dict = NULL; + } + + return dict; +} + +PyDoc_STRVAR(kvpy_kypy_read__doc__, +"kvpy_read(dir, base, block) -> dictionary\n\ +dir is directory\n\ +base may be the emtpy string\n\ +block is 1/0 indicating whether to wait for a frame if none is ready."); + +PyDoc_STRVAR(kvpy_kypy_write__doc__, +"kvpy_write(dir, base, dict) \n\ +dir is directory\n\ +base is the spool basename\n\ +dict is the dictionary to spool out"); + +PyDoc_STRVAR(kvpy_kypy_stat__doc__, +"kvpy_stat(dir, base) -> dictionary\n\ +dir is directory\n\ +base may be the emtpy string"); + + +static PyMethodDef kvpy_methods[] = { + {"kvpy_read", kvpy_read, METH_VARARGS, kvpy_kypy_read__doc__}, + {"kvpy_write", kvpy_write, METH_VARARGS, kvpy_kypy_write__doc__}, + {"kvpy_stat", kvpy_stat, METH_VARARGS, kvpy_kypy_stat__doc__}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initkvpy(void) +{ + Py_InitModule("kvpy", kvpy_methods); +} diff --git a/kvpy/utils/README b/kvpy/utils/README new file mode 100644 index 0000000..78d6407 --- /dev/null +++ b/kvpy/utils/README @@ -0,0 +1,5 @@ +These scripts exercise the kvpy module which reads key-value spools within Python. + +read.py : tries to read one frame from the spool subdirectory (non-blocking) +read_all.py: tries to read all frames from the spool subdirectory (blocking) +runtest.sh : invokes another utility to write a frame to the spool then runs read.py diff --git a/kvpy/utils/read.py b/kvpy/utils/read.py new file mode 100755 index 0000000..d69fdc1 --- /dev/null +++ b/kvpy/utils/read.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +# so we don't have to install kvpy.so (or we could +# have set PYTHONPATH to include its dir beforehand) +import sys +sys.path.append("../build/lib.linux-i686-2.6") + +import kvpy +d = kvpy.kvpy_read("spool","base",0) +for key in d.keys(): + print "key: " + key + " value: " + d[key] diff --git a/kvpy/utils/read_all.py b/kvpy/utils/read_all.py new file mode 100755 index 0000000..879a2a2 --- /dev/null +++ b/kvpy/utils/read_all.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +# so we don't have to install kvpy.so (or we could +# have set PYTHONPATH to include its dir beforehand) +import sys +sys.path.append("../build/lib.linux-i686-2.6") + +import kvpy +while True: + d = kvpy.kvpy_read("spool","",1) + for key in d.keys(): + print "key: " + key + " value: " + d[key] diff --git a/kvpy/utils/runtest.sh b/kvpy/utils/runtest.sh new file mode 100755 index 0000000..7d29aa6 --- /dev/null +++ b/kvpy/utils/runtest.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +SPW=../../tests/spw +export PYTHONPATH="../build/lib.linux-i686-2.6" + +# sanity checks +if [ ! -d spool ]; then mkdir spool; fi +if [ ! -x ${SPW} ]; then echo "script requires ${SPW}"; exit -1; fi + +# write out a frame and read it from python +${SPW} -b base spool +./read.py diff --git a/kvpy/utils/speed.py b/kvpy/utils/speed.py new file mode 100755 index 0000000..365fee5 --- /dev/null +++ b/kvpy/utils/speed.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +# so we don't have to install kvpy.so (or we could +# have set PYTHONPATH to include its dir beforehand) +import sys +sys.path.append("../build/lib.linux-i686-2.6") + +from datetime import datetime; + +import kvpy +d = {"key":"value","key2":"value2"} + +# write test +t1 = datetime.now() +for i in range(100000): + kvpy.kvpy_write("/tmp/spool","wr",d) +t2 = datetime.now() +t3 = t2 - t1 +print "write:", int(100 / (t3.seconds + (t3.microseconds/1000000.0))), "kfps" + +# read test +t1 = datetime.now() +for i in range(100000): + kvpy.kvpy_read("/tmp/spool","wr",0) +t2 = datetime.now() +t3 = t2 - t1 +print "read: ", int(100 / (t3.seconds + (t3.microseconds/1000000.0))), "kfps" + diff --git a/kvpy/utils/write.py b/kvpy/utils/write.py new file mode 100755 index 0000000..91f675b --- /dev/null +++ b/kvpy/utils/write.py @@ -0,0 +1,10 @@ +#!/usr/bin/python + +# so we don't have to install kvpy.so (or we could +# have set PYTHONPATH to include its dir beforehand) +import sys +sys.path.append("../build/lib.linux-i686-2.6") + +import kvpy +d = {"key":"value","key2":"value2"} +kvpy.kvpy_write("spool","wr",d) diff --git a/kvspool.c b/kvspool.c new file mode 100644 index 0000000..5d80984 --- /dev/null +++ b/kvspool.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include "kvspool.h" +#include "kvspool_internal.h" + +void sp_oom(void) { + fprintf(stderr, "out of memory\n"); + exit(-1); +} + +void* kv_set_new(void) { + kvset_t *set; + if ( (set = malloc(sizeof(kvset_t))) == NULL) sp_oom(); + memset(set,0,sizeof(*set)); + return set; +} + +void kv_set_clear(void*_set) { + kvset_t *set = (kvset_t*)_set; + kv_t *kv, *tmp; + HASH_ITER(hh, set->kvs, kv, tmp) { + HASH_DEL(set->kvs, kv); + free(kv->key); free(kv->val); free(kv); + } + if (set->base) { + free(set->base); + set->base=NULL; + } + if (set->img || set->len) { + assert(set->img && set->len); + free(set->img); set->img=NULL; + set->len=0; + } +} + +void kv_set_dump(void*_set,FILE *out) { + kvset_t *set = (kvset_t*)_set; + kv_t *kv; + char c; + int i; + + kv=NULL; + while ( (kv=kv_next(set,kv))) { + fprintf(out," %.*s: ", kv->klen, kv->key); + switch(kv->fmt) { + case 'c': fprintf(out,"%x",(uint32_t)(*(uint8_t*)kv->val)); break; + case 's': fprintf(out,"%s", (char*)kv->val); break; + case 'u': fprintf(out,"%u",*(uint32_t*)kv->val); break; + case 'd': fprintf(out,"%d",*( int32_t*)kv->val); break; + case 'b': fprintf(out,"(buffer of length %u)",kv->vlen); break; + case 'n': fprintf(out,"%u",(uint32_t)(*(uint16_t*)kv->val)); break; + case 'm': fprintf(out,"%d",( int32_t)(*( int16_t*)kv->val)); break; + case 'U': fprintf(out,"%lu",*(uint64_t*)kv->val); break; + case 'D': fprintf(out,"%ld",*( int64_t*)kv->val); break; + case 'f': fprintf(out,"%f",*( double*)kv->val); break; + default: fprintf(out,"unknown format conversion '%c'", kv->fmt); break; + } + fprintf(out,"\n"); + } +} + +void kv_set_free(void*_set) { + kvset_t *set = (kvset_t*)_set; + kv_t *kv, *tmp; + HASH_ITER(hh, set->kvs, kv, tmp) { + HASH_DEL(set->kvs, kv); + free(kv->key); free(kv->val); + free(kv); + } + assert(set->kvs == NULL); + if (set->base) free(set->base); + if (set->img || set->len) { + assert(set->img && set->len); + free(set->img); + set->len=0; + } + free(set); +} + +char *kv_set_base(void*_set) { + kvset_t *set = (kvset_t*)_set; + return set->base; +} + +kv_t *kv_get(void*_set, char *key) { + kv_t *kv; + kvset_t *set = (kvset_t*)_set; + HASH_FIND(hh, set->kvs, key, strlen(key), kv); + return kv; +} + +void _kv_add(void*_set, const char *key, int klen, char fmt, const char *val, int vlen) { + kvset_t *set = (kvset_t*)_set; + assert(klen); //assert(vlen); + kv_t *kv; + + /* check if we're replacing an existing key */ + HASH_FIND(hh, set->kvs, key, klen, kv); + if (kv) { /* yes, free the old value and replace it */ + free(kv->val); + if ( (kv->val = malloc(vlen+1)) == NULL) sp_oom(); kv->vlen = vlen; + memcpy(kv->val, val, vlen); kv->val[vlen]='\0'; + kv->fmt = fmt; + return; + } + /* new key. deep copy the key/val and add it, null term for convenience */ + if ( (kv = malloc(sizeof(*kv))) == NULL) sp_oom(); + if ( (kv->key = malloc(klen+1)) == NULL) sp_oom(); kv->klen = klen; + if ( (kv->val = malloc(vlen+1)) == NULL) sp_oom(); kv->vlen = vlen; + memcpy(kv->key, key, klen); kv->key[klen]='\0'; + memcpy(kv->val, val, vlen); kv->val[vlen]='\0'; + kv->fmt = fmt; + HASH_ADD_KEYPTR(hh,set->kvs,kv->key,kv->klen,kv); +} + +/* addt: the preferred way to add to a set. key is string, format is explicit */ +void kv_addt(void*_set, const char *key, char fmt, const void *val, int vlen) { + _kv_add(_set, key, strlen(key), fmt, val, vlen); +} + +void kv_add(void*_set, const char *key, int klen, const char *val, int vlen) { + _kv_add(_set, key, klen, 's', val, vlen); +} + +int kv_len(void*_set) { + kvset_t *set = (kvset_t*)_set; + return set->kvs ? (HASH_COUNT(set->kvs)) : 0; +} + +kv_t *kv_next(void*_set,kv_t *kv) { + kvset_t *set = (kvset_t*)_set; + if (!kv) return set->kvs; /* get first element */ + return kv->hh.next; +} + diff --git a/kvspool.h b/kvspool.h new file mode 100644 index 0000000..381dba5 --- /dev/null +++ b/kvspool.h @@ -0,0 +1,69 @@ +#ifndef _KVSPOOL_H_ +#define _KVSPOOL_H_ + +#include +#include "uthash.h" + +/* kvspool: an API for dealing with a set of key-value pairs */ + +#define KV_BASE_MAX 256 /* max length of 'base' for spool writer */ + +/****************************************************************************** + * key-value set API + *****************************************************************************/ +typedef struct { + char *key; + int klen; + char fmt; /* format of the value; s/i/... */ + char *val; + int vlen; + UT_hash_handle hh; /* internal */ +} kv_t; + + +#if defined __cplusplus +extern "C" { +#endif + +void* kv_set_new(void); +void kv_set_free(void*); +void kv_set_clear(void*); +void kv_set_dump(void *set,FILE *out); +char *kv_set_base(void *); +void kv_add(void*set, const char *key, int klen, const char *val, int vlen); +void kv_addt(void*set, const char *key, char fmt, const void *val, int vlen); +kv_t *kv_get(void*set, char *key); +#define kv_adds(set, key, val) kv_add(set,key,strlen(key),val,strlen(val)) +int kv_len(void*set); +kv_t *kv_next(void*set,kv_t *kv); + +/****************************************************************************** + * spooling API + *****************************************************************************/ +void *kv_spoolreader_new(const char *dir, const char *base); +int kv_spool_read(void*sp, void *set, int blocking); +void kv_spoolreader_free(void*); + +void *kv_spoolwriter_new(const char *dir, const char *base); +int kv_spool_write(void*sp, void *set); +void kv_spoolwriter_free(void*); +void sp_attrition(char *dir); + +/****************************************************************************** + * special purpose API + *****************************************************************************/ +typedef struct { char base[KV_BASE_MAX]; int pct_consumed; } kv_stat_t; +int kv_stat(const char *dir, const char *base, kv_stat_t **stats); +void sp_reset(const char *dir, const char *base); + +typedef struct { + size_t dir_max; + size_t file_max; /* this will be automatically set to 10% of dir_max */ +} kv_spool_options_t; +extern kv_spool_options_t kv_spool_options; + +#if defined __cplusplus +} +#endif + +#endif diff --git a/kvspool_attrition.c b/kvspool_attrition.c new file mode 100644 index 0000000..cfcf425 --- /dev/null +++ b/kvspool_attrition.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utarray.h" + +#include "kvspool.h" +#include "kvspool_internal.h" + +typedef struct { + int file_idx; + int wr_locked; + int consumed; + struct stat sb; +} kv_spool_ainfo_t; + +static UT_icd ainfo_icd = {sizeof(kv_spool_ainfo_t), NULL, NULL, NULL }; +static int attrition_sort(const void *_a, const void *_b) { + kv_spool_ainfo_t *a = (kv_spool_ainfo_t*)_a; + kv_spool_ainfo_t *b = (kv_spool_ainfo_t*)_b; + /* writer-locked ones sort after unlocked ones */ + if (a->wr_locked != b->wr_locked) return (a->wr_locked - b->wr_locked); + /* consumed ones sort _before_ unconsumed ones */ + if (a->consumed != b->consumed) return (b->consumed - a->consumed); + /* oldest modify time sorts first */ + return a->sb.st_mtime - b->sb.st_mtime; +} + +static uint32_t get_rpos(char *sp_file) { + uint32_t rpos=0; + char *sr_file; + int fd=-1, len; + + sr_file = strdup(sp_file); + len = strlen(sr_file); + sr_file[len-1] = 'r'; + if ( (fd = open(sr_file,O_RDONLY)) == -1) goto done; + if (read(fd,&rpos,sizeof(rpos)) != sizeof(rpos)) goto done; + /* success */ + + done: + free(sr_file); + if (fd != -1) close(fd); + return rpos; +} + +static void sp_get_attrition_order(UT_array *files, UT_array *ainfo, + size_t *spool_sz) { + kv_spool_ainfo_t *ai; + char **f, *file; + int fd; + + *spool_sz = 0; + + f=NULL; + while ( (f=(char**)utarray_next(files,f))) { + file = *f; + utarray_extend_back(ainfo); + ai = (kv_spool_ainfo_t*)utarray_back(ainfo); + ai->file_idx = utarray_eltidx(files,f); + if (stat(file, &ai->sb) == -1) continue; + *spool_sz += ai->sb.st_size; + ai->consumed = (get_rpos(file) >= ai->sb.st_size) ? 1 : 0; + /* test whether a writer has a lock on this spool file */ + ai->wr_locked = 0; + if ( (fd = open(file,O_RDONLY)) != -1) { + if (flock(fd,LOCK_EX|LOCK_NB) == -1) ai->wr_locked=1; + close(fd); + } + } + utarray_sort(ainfo, attrition_sort); +} + +/* periodic spool attrition. caps the collective size of the spool directory. + * if reached, unlink spool files. prefer to unlink consumed spools, otherwise + * unconsumed spools. Those having oldest last-modified timestamps go first. + */ +void sp_attrition(char *dir) { + sp_readlimits(dir); /* reread in case the limits file was updated by hand */ + if (kv_spool_options.dir_max == 0) return; /* unlimited - never attrition */ + kv_spool_ainfo_t *ai; + char **f, *file; + size_t spool_sz, implied_max; + UT_array *files=NULL, *ainfo=NULL; + utarray_new(files, &ut_str_icd); + sp_readdir(dir, NULL, ".sp", files); +#if 0 + /* bail out without having to 'stat' all the files in the spool, if we can */ + implied_max = utarray_len(files) * kv_spool_options.file_max; + if (implied_max < kv_spool_options.dir_max) goto done; + /* enough files to justify tallying up their size and attrition as needed */ +#endif + utarray_new(ainfo, &ainfo_icd); + sp_get_attrition_order(files, ainfo, &spool_sz); + if (spool_sz < kv_spool_options.dir_max) goto done; + /* cull as many files as needed to bring spool size down below the cap */ + ai=NULL; + while ( (ai=(kv_spool_ainfo_t*)utarray_next(ainfo,ai))) { + f = (char**)utarray_eltptr(files, ai->file_idx); assert(f); + file = *f; + //fprintf(stderr,"unlinking %s of size %lu\n", file, (long)ai->sb.st_size); + if (unlink(file) == 0) { + spool_sz -= ai->sb.st_size; + /* also unlink the .sr file */ + file[strlen(file)-1]='r'; + unlink(file); + } + if (spool_sz < kv_spool_options.dir_max) break; + } + + done: + if (files) utarray_free(files); + if (ainfo) utarray_free(ainfo); +} + diff --git a/kvspool_internal.h b/kvspool_internal.h new file mode 100644 index 0000000..40a689b --- /dev/null +++ b/kvspool_internal.h @@ -0,0 +1,38 @@ +#ifndef _KVSPOOL_INTERNAL_H_ +#define _KVSPOOL_INTERNAL_H_ + +#include "kvspool.h" +#include "utarray.h" + +/******************************************************************************* + * internal structures and prototypes + ******************************************************************************/ +/* magic prefix at the start of the spool file */ +#define KVSPOOL_MAGIC "KV+SPOOL" + +/* (reader): scan for new readable spools when > x seconds elapse */ +#define KVSPOOL_RESCAN_INTERVAL 10 /* seconds */ + +/* (writer) attrition as needed to keep the total spool size approx under x */ +/* 1 GB is a default but this can be configured using the 'limits' file. */ +#define KVSPOOL_DIR_MAX (1*1024*1024*1024) + +/* individual files within the spool directory are limited also, by default + * to size (KVSPOOL_DIR_MAX / 10). However we need to cap this at <4GB since + * we use a 32-bit offset (stored in the .sr file) to mark the read position */ +#define KVSPOOL_FILE_MAX (1*1024*1024*1024) + +void sp_oom(void); +int sp_readdir(const char *dir, const char *base, const char *suffix, UT_array *files); +int sp_strsort(const void *_a, const void *_b); +int kv_write_raw_frame(void *sp, void *img, size_t len); +void sp_readlimits(const char *dir); +void sp_attrition(char *dir); +void sp_keep_maxseq(UT_array *files); +typedef struct { + char *base; /* base for this set, valid when read from a spool or network */ + void *img; /* the img and len refer to the serialized image of the kvset */ + size_t len; /* populated when a set is read from spool or publisher */ + kv_t *kvs; +} kvset_t; +#endif diff --git a/kvspoolr.c b/kvspoolr.c new file mode 100644 index 0000000..03ac7b7 --- /dev/null +++ b/kvspoolr.c @@ -0,0 +1,449 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "kvspool_internal.h" +#include "utstring.h" +#include "tpl.h" + +#define INTERNAL_RESCAN_INTERVAL_SEC (10) + +typedef struct { + char *srpath; /* e.g. /tmp/myspool/spool.123456789.999-000.sr */ + char *sppath; /* e.g. /tmp/myspool/spool.123456789.999-000.sp */ + char *spbase; /* e.g. spool */ + int retries; /* to detect corrupt spool */ + int sp_fd; + int sr_fd; + UT_hash_handle sppath_hh; + unsigned pos; + time_t last; +} kv_spoolrec_t; + +typedef struct { + char *dir; + char *base; + kv_spoolrec_t *spools; + struct inotify_event *ev; + size_t ev_sz; + /* for periodic rescan of spool directory for new files */ + int need_rescan; + time_t last_scan; + /* scratch space */ + UT_string *tmp; +} kv_spoolr_t; + + +static void unlock_spool(kv_spoolr_t *sp, kv_spoolrec_t *r) { + HASH_DELETE(sppath_hh,sp->spools,r); + if (r->srpath) free(r->srpath); + if (r->sppath) free(r->sppath); + if (r->spbase) free(r->spbase); + close(r->sr_fd); + close(r->sp_fd); + free(r); +} + +static void validate_lock_spool(kv_spoolr_t *sp, char *path) { + kv_spoolrec_t *r; + struct stat sb; + int plen, fd; + + plen = strlen(path); + + /* already locked on the spool? nothing to do. */ + HASH_FIND(sppath_hh, sp->spools, path, plen, r); + if (r) return; + + /* + * we have a new spool file to lock, if it checks out. we need to be able to + * lock the spool reader marker, open the spool file for reading, etc. + * we also want to ignore locking fully spent (max-sized) spools unless they + * have any unconsumed data. spent spools remain on disk til writer unlinks + * them to make room at its discretion. + */ + + char *sppath = strdup(path); + char *srpath = strdup(path); srpath[plen-1] = 'r'; + /* copy the base from the path, e.g. /some/spool/BASE.123456789.999-0.sp */ + char *slash = strrchr(sppath,'/'); assert(slash); + char *spbase = strdup(slash+1); + char *dot = strchr(spbase,'.'); assert(dot); + *dot = '\0'; + + if ( (r = malloc(sizeof(*r))) == NULL) sp_oom(); + memset(r,0,sizeof(*r)); + r->srpath = srpath; + r->sppath = sppath; + r->spbase = spbase; + r->retries = 0; + if ( (r->sp_fd = open(r->sppath, O_RDONLY)) == -1) goto fail; + if ( (r->sr_fd = open(r->srpath, O_RDWR)) == -1) goto fail; + if (flock(r->sr_fd, LOCK_EX|LOCK_NB) == -1) goto fail; + if ((fstat(r->sr_fd, &sb) == -1) || (sb.st_size != sizeof(r->pos))) goto fail; + if (read(r->sr_fd, &r->pos, sizeof(r->pos)) != sizeof(r->pos)) goto fail; + if ((fstat(r->sp_fd, &sb) == -1) || (sb.st_size < r->pos)) goto fail; + if ((r->pos > kv_spool_options.file_max) && (sb.st_size <= r->pos)) goto fail; + HASH_ADD_KEYPTR(sppath_hh,sp->spools,r->sppath,plen,r); + return; + + fail: + if (r->srpath) free(r->srpath); + if (r->sppath) free(r->sppath); + if (r->spbase) free(r->spbase); + if (r->sp_fd != -1) close(r->sp_fd); + if (r->sr_fd != -1) close(r->sr_fd); + free(r); + return; +} + +static int spool_sort(kv_spoolrec_t *a, kv_spoolrec_t *b) { + char *ahyph = strrchr(a->sppath,'-'), *bhyph = strrchr(b->sppath,'-'); + assert(ahyph && bhyph); + int c, alen=ahyph-a->sppath, blen=bhyph-b->sppath; + int min = (alen < blen) ? alen : blen; + if (alen != blen) return strncmp(a->sppath, b->sppath, min); + /* identical up through trailing sequence number. numerically compare + * the sequence numbers (note 1 < 10 is not true using strcmp) */ + int aseq,bseq; + c=sscanf(ahyph+1,"%u",&aseq); assert(c==1); + c=sscanf(bhyph+1,"%u",&bseq); assert(c==1); + return aseq-bseq; +} + +/* lock the available input spools. this function can get called many times + * during a spool reader's lifetime as files in the spool dir get created. + * Even though inotify tells us exactly which files were modified, we just + * rescan the whole spool directory, add new locks and update our state. */ +static int rescan_spools(kv_spoolr_t *sp) { + kv_spoolrec_t *r, *tmp; + char *path, **p; + int rc = -1; + + UT_array *files; + utarray_new(files, &ut_str_icd); + + if (sp_readdir(sp->dir, sp->base, ".sp", files) == -1) goto done; + + /* first lock all the spools that are listed in the directory */ + p = NULL; + while ( (p = (char**)utarray_next(files,p))) { + path = *p; + validate_lock_spool(sp, path); + } + + /* unlock any spools that aren't in the directory (were deleted) */ + HASH_ITER(sppath_hh, sp->spools, r, tmp) { + p = utarray_find(files, &r->sppath, sp_strsort); + if (!p) unlock_spool(sp,r); + } + + sp->last_scan = time(NULL); + sp->need_rescan = 0; + rc = 0; + HASH_SRT(sppath_hh, sp->spools, spool_sort); + + done: + utarray_free(files); + return rc; +} + +static int update_rpos(kv_spoolr_t *sp, kv_spoolrec_t *r, size_t sz) { + r->pos += sz; + if ((lseek(r->sr_fd,0,SEEK_SET) == -1) || + (write(r->sr_fd,&r->pos,sizeof(r->pos)) != sizeof(r->pos))) { + fprintf(stderr,"failed to update srmark: %s\n", strerror(errno)); + r->pos -= sz; + sp->need_rescan=1; + return -1; + } + return 0; /* success */ +} + +static void fill_set(void *img, size_t sz, kv_spoolr_t *sp, kvset_t *set) { + tpl_node *tn; + char *key; + char fmt; + tpl_bin vb; + + kv_set_clear(set); + + tn = tpl_map("A(scB)", &key, &fmt, &vb); + if (tpl_load(tn, TPL_MEM, img, sz) == -1) { + fprintf(stderr, "tpl_load failed (sz %d)\n", (int)sz); + return; + } + while( tpl_unpack(tn,1) > 0 ) { + kv_addt(set, key, fmt, vb.addr, vb.sz); + free(key); + free(vb.addr); + } + tpl_free(tn); + set->img = img; + set->len = sz; +} + +/* see if one frame is available from any spool file we're locked on */ +static int read_frame(kv_spoolr_t *sp, kvset_t *set) { + kv_spoolrec_t *r, *tmp; + struct stat sb; + size_t sz; + void *img; + int rc; + + HASH_ITER(sppath_hh, sp->spools, r, tmp) { + if (fstat(r->sp_fd, &sb) == -1) { sp->need_rescan=1; continue; } + if (sb.st_size < sizeof(off_t)) continue; + if (sb.st_size - sizeof(off_t) <= r->pos) continue; + if (lseek(r->sp_fd, r->pos, SEEK_SET) == -1) {sp->need_rescan=1; continue; } + if (tpl_gather(TPL_GATHER_BLOCKING, r->sp_fd, &img, &sz) <= 0) { + if (++r->retries > 3) { + fprintf(stderr,"possible spool corruption on %s: unlinking\n", r->sppath); + unlink(r->srpath); + unlink(r->sppath); + sp->need_rescan=1; + } + continue; + } + else if (r->retries) r->retries=0; + if (update_rpos(sp,r,sz) == -1) {free(img); continue;} + r->last = time(NULL); + fill_set(img,sz,sp,set); + assert(r->spbase); set->base = strdup(r->spbase); + //do not free(img); that is done in kv_set_free + return 1; /* success */ + } + return 0; /* no frame to read */ +} + +/* used to fully qualify a filename into path for use in hash lookup */ +static void fully_qualify(kv_spoolr_t *sp, char *name, char **path, int *plen) { + utstring_clear(sp->tmp); + utstring_printf(sp->tmp, "%s/%s", sp->dir, name); + *path = utstring_body(sp->tmp); + *plen = utstring_len(sp->tmp); +} + +static int prefix_match(char *file, char *base) { + char *dot = strchr(file,'.'); + if (!dot) return 0; + if (!memcmp(file,base,dot-file)) return 1; + return 0; +} + +/* block on event notification waiting for file modification */ +static int wait_for_event(kv_spoolr_t *sp) { + int rc=-1, ifd=-1; + + assert(sp && sp->dir); + + if ( (ifd = inotify_init()) == -1) goto done; + if (inotify_add_watch(ifd, sp->dir, IN_ALL_EVENTS) == -1) { + fprintf(stderr,"failed to inotify on %s: %s\n", sp->dir, strerror(errno)); + goto done; + } + + fd_set inotify_fdset; FD_ZERO(&inotify_fdset); FD_SET(ifd,&inotify_fdset); + struct timeval timeout = {.tv_sec = INTERNAL_RESCAN_INTERVAL_SEC, .tv_usec=0}; + if (select(ifd+1, &inotify_fdset, NULL, NULL, &timeout) == -1) { + fprintf(stderr,"select error: %s\n",strerror(errno)); + if (errno != EINTR) goto done; + } + rc=0; + + done: + if (ifd != -1) close(ifd); + sp->need_rescan=1; + return rc; +} + +/******************************************************************************* + * Spool reader API + * base may be NULL to read all spools in the dir + ******************************************************************************/ +void *kv_spoolreader_new(const char *dir, const char *base) { + assert(dir); + int rc = -1; + + kv_spoolr_t *sp; + if ( (sp = malloc(sizeof(*sp))) == NULL) sp_oom(); + memset(sp,0,sizeof(*sp)); + sp->dir = strdup(dir); + sp->base = base ? strdup(base) : NULL; + sp->spools = NULL; + sp->ev_sz = sizeof(*(sp->ev)) + PATH_MAX; + if ( (sp->ev = malloc(sp->ev_sz)) == NULL) sp_oom(); + sp->need_rescan = 0; + sp_readlimits(dir); + utstring_new(sp->tmp); + + if (rescan_spools(sp) == -1) goto done; + rc = 0; // success + + done: + if (rc == -1) { + if (sp->dir) free(sp->dir); + if (sp->base) free(sp->base); + if (sp->ev) free(sp->ev); + if (sp->tmp) utstring_free(sp->tmp); + assert(sp->spools == NULL); + free(sp); + sp = NULL; + } + return sp; +} + +/* Here's the all important spool reader function that reads + * a spool frame and populates the set from it. It can be + * blocking, which will wait for a frame to appear in the spool, + * or non-blocking which will return if the spool doesn't have + * any unread frames at the moment. + */ +int kv_spool_read(void *_sp, void *_set, int blocking) { + kv_spoolr_t *sp = (kv_spoolr_t*)_sp; + kvset_t *set = (kvset_t*)_set; + kv_t *kv, *tmp; + + /* check whether we're due for periodic spool rescan. + * we do this because, we don't get inotify file events + * after handing a set back to the caller. so new spoolfiles + * created outside of the lifetime of this function need + * to be detected by a periodic rescan. Flag also gets set + * if we get a change event on a spool we aren't locked on, + * or a deletion event on a spool we are locked on. + */ + if ((time(NULL)-sp->last_scan) > KVSPOOL_RESCAN_INTERVAL) { + sp->need_rescan=1; + } + + again: + if (sp->need_rescan) {if (rescan_spools(sp) == -1) return -1;} + if (read_frame(sp,set)) return 1; + if (!blocking) return 0; /* no frame ready */ + if (wait_for_event(sp) >= 0) goto again; + return -1; /* if we got here, a blocking wait failed; error out */ + +} + +void kv_spoolreader_free(void *_sp) { + kv_spoolr_t *sp = (kv_spoolr_t*)_sp; + kv_spoolrec_t *rec, *tmp; + + if (sp->dir) free(sp->dir); + if (sp->base) free(sp->base); + if (sp->ev) free(sp->ev); + if (sp->tmp) utstring_free(sp->tmp); + + HASH_ITER(sppath_hh, sp->spools, rec, tmp) { + HASH_DELETE(sppath_hh,sp->spools,rec); + if (rec->srpath) free(rec->srpath); + if (rec->sppath) free(rec->sppath); + if (rec->spbase) free(rec->spbase); + if (rec->sp_fd != -1) close(rec->sp_fd); + if (rec->sr_fd != -1) close(rec->sr_fd); + free(rec); + } + + free(sp); +} + +void sp_reset(const char *dir, const char *base) { + char *path, **p; + int sr_fd,rp; + + UT_array *files; + utarray_new(files, &ut_str_icd); + + if (sp_readdir(dir, base, ".sr", files) == -1) goto done; + + p = NULL; + while ( (p = (char**)utarray_next(files,p))) { + path = *p; + if ( (sr_fd = open(path, O_RDWR)) == -1) continue; + if (flock(sr_fd, LOCK_EX|LOCK_NB) == -1) {close(sr_fd); continue;} + lseek(sr_fd,0,SEEK_SET); + rp = strlen(KVSPOOL_MAGIC); + if (write(sr_fd, &rp, sizeof(rp)) != sizeof(rp)) unlink(path); + close(sr_fd); + } + + done: + utarray_free(files); +} + +/* get the percentage consumed for each spool in dir (limited to base + unless its NULL). caller must free the returned stats. + returns -1 on error otherwise the number of structs in stats */ +int kv_stat(const char *dir, const char *base, kv_stat_t **stats) { + char **f, *file, *dot, *cur_base, *lst_base, *filepart; + uint32_t sz, spsz; + uint64_t gsz=0, gspsz=0; + int fd, rr, rc = -1; + struct stat sb; + kv_stat_t *s; + + *stats = NULL; + + UT_icd kv_stat_icd = {sizeof(kv_stat_t), NULL, NULL, NULL }; + UT_array *out; utarray_new(out, &kv_stat_icd); + UT_string *last_base; utstring_new(last_base); + UT_string *current_base; utstring_new(current_base); + UT_array *files; utarray_new(files, &ut_str_icd); + + if (sp_readdir(dir, base, ".sr", files) == -1) goto done; + + f = NULL; + while ( (f=(char**)utarray_next(files,f))) { + file = *f; + + /* we'll accumulate grand totals for consecutive spool files with + * the same base (they are sorted for us); when the base changes + * and at the end, we emit the grand totals for the preceding base. */ + filepart = strrchr(file,'/'); if (filepart) filepart++; else filepart = file; + dot = strchr(filepart,'.'); if (dot-filepart+1 > KV_BASE_MAX) continue; + utstring_clear(current_base); + utstring_bincpy(current_base,filepart,dot-filepart); + cur_base = utstring_body(current_base); + + /* get size consumed (sz) and total spool size (spsz) for current sp/sr */ + if ( (fd=open(file,O_RDONLY)) == -1) continue; + rr = read(fd,&sz,sizeof(sz)); close(fd); if (rr != sizeof(sz)) continue; + file[strlen(file)-1]='p'; spsz = (stat(file,&sb) == -1) ? 0 : sb.st_size; + if (spsz>=8) {spsz-=8; sz-=8;} else continue; /* ignore spool preamble */ + + /* if base switched, emit record for preceding base */ + if ( (*(lst_base=utstring_body(last_base))!='\0') && strcmp(lst_base,cur_base)) { + utarray_extend_back(out); s = (kv_stat_t*)utarray_back(out); + strncpy(s->base,lst_base,sizeof(s->base)); + s->pct_consumed = gspsz ? (int)(gsz * 100.0 / gspsz) : 100; + gsz = 0; gspsz = 0; /* reset */ + } + gsz += sz; gspsz += spsz; + utstring_clear(last_base); utstring_printf(last_base,"%s",cur_base); + } + /* emit final one (if there was one) */ + if ( (*(lst_base=utstring_body(last_base))) != '\0') { + utarray_extend_back(out); s = (kv_stat_t*)utarray_back(out); + strncpy(s->base,lst_base,sizeof(s->base)); + s->pct_consumed = gspsz ? (int)(gsz * 100.0 / gspsz) : 100; + } + + /* copy out results to final buffer to return */ + rc = utarray_len(out); if (rc == 0) goto done; + *stats = malloc(rc * sizeof(kv_stat_t)); if (!stats) {rc = -1; goto done; } + memcpy(*stats, utarray_front(out), rc * sizeof(kv_stat_t)); + + done: + utstring_free(last_base); + utstring_free(current_base); + utarray_free(files); + utarray_free(out); + return rc; +} diff --git a/kvspoolw.c b/kvspoolw.c new file mode 100644 index 0000000..2010ded --- /dev/null +++ b/kvspoolw.c @@ -0,0 +1,405 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utstring.h" +#include "utarray.h" +#include "tpl.h" + +#include "kvspool.h" +#include "kvspool_internal.h" + +typedef struct { + char *dir; + char *base; + char *path; + int fd; + size_t noc; +} kv_spoolw_t; + +#define MIN(x,y) (x 0) { + b[rc] = '\0'; + cv = sscanf(b,"%ld%c", &dir_max, &unit); + switch(cv) { + case 2: /* convert number w/units to bytes */ + switch(unit) { + case 't': case 'T': dir_max *= 1024; /* fall through */ + case 'g': case 'G': dir_max *= 1024; /* fall through */ + case 'm': case 'M': dir_max *= 1024; /* fall through */ + case 'k': case 'K': dir_max *= 1024; break; + case '\r': case '\n': case ' ': case '\t': break; + default: /* unsupported unit */ goto done; + } + /* fall through to case 1 */ + case 1: kv_spool_options.dir_max = dir_max; break; + } + } + } + + done: + if (fd != -1) close(fd); + utstring_free(s); + kv_spool_options.file_max = MIN(kv_spool_options.dir_max/10,KVSPOOL_FILE_MAX); +} + +int sp_readdir(const char *dir, const char *base, const char *suffix, UT_array *files) { + int rc = -1, blen, nlen, slen; + struct dirent *dent; + char *name, *path; + UT_string *s; + DIR *d; + + utstring_new(s); + utarray_clear(files); + blen = base ? strlen(base) : 0; + slen = suffix ? strlen(suffix) : 0; + + if ( (d = opendir(dir)) == NULL) { + fprintf(stderr, "failed to opendir [%s]: %s\n", dir, strerror(errno)); + goto done; + } + + while ( (dent = readdir(d)) != NULL) { + if (dent->d_type != DT_REG) continue; + name = dent->d_name; + nlen = strlen(name); + // verify base and suffix match + if (blen && strncmp(base,name,blen)) continue; + if (blen && (name[blen] != '.')) continue; + if (slen && (nlen < slen)) continue; + if (slen && memcmp(&name[nlen-slen],suffix,slen)) continue; + // ok, fully qualify it and push it + utstring_clear(s); + utstring_printf(s, "%s/%s", dir, name); + path = utstring_body(s); + utarray_push_back(files, &path); + } + utarray_sort(files, sp_strsort); + rc = 0; // success + + done: + utstring_free(s); + if (d) closedir(d); + return rc; +} + +/* sequence number is the last number in a filename eg: spool.1234567.123-004.sp + * this function retains only names which are the highest in each sequence */ +void sp_keep_maxseq(UT_array *files) { + char *path, **p, *last=NULL, *hyphen; + int i,llen; + UT_string *s; + utstring_new(s); + UT_array *ms_files; + utarray_new(ms_files, &ut_str_icd); + + utarray_sort(files, sp_strsort); + p=NULL; + while( (p=(char**)utarray_next(files,p))) { + path = *p; + last = utstring_body(s); + hyphen = strchr(last,'-'); + llen = hyphen ? (hyphen-last) : 0; + if (llen && memcmp(path,last,llen)) { + utarray_push_back(ms_files,&last); + } + utstring_clear(s); + utstring_bincpy(s,path,strlen(path)); + } + if (last) utarray_push_back(ms_files,&last); + + utarray_clear(files); + utarray_inserta(files,ms_files,0); + + utstring_free(s); + utarray_free(ms_files); +} + +/* first word of spool file is a magic marker */ +static int has_spool_magic(int fd, int create) { + struct stat sb; + int len = strlen(KVSPOOL_MAGIC); assert(len == 8); + char mark[8],sig[3]; + int rc=-1; + off_t of; + + if (create) { + if (write(fd,KVSPOOL_MAGIC,8) != 8) goto done; + } else { + lseek(fd,0,SEEK_SET); + if (read(fd,mark,8) != 8) goto done; + if (memcmp(mark,KVSPOOL_MAGIC,8)) goto done; + if ( (of=lseek(fd,0,SEEK_END)) > 8) { + if (lseek(fd,-1*sizeof(of),SEEK_END) == -1) goto done; + if (read(fd, &of, sizeof(of)) != sizeof(of)) goto done; + if (lseek(fd,-1*(of+sizeof(of)),SEEK_END) == -1) goto done; + if (read(fd, sig, sizeof(sig)) != sizeof(sig)) goto done; + if (memcmp(sig,"tpl",sizeof(sig))) goto done; + } + } + rc=0; /* success */ + + done: + return rc; +} + +// just change trailing .sp to .sr and verify existence +// returns 0 on success; -1 on error / srmark not found +static int has_srmark_file(char *path, int create) { + int plen = strlen(path); + char *rpath = NULL; + struct stat sb; + int fd=-1, rc = -1, rp; + + /* sanity check - path should end in .sp */ + if (plen < 3) goto done; + if (memcmp(&path[plen-3],".sp",3)) goto done; + + /* change .sp to .sr */ + rpath = strdup(path); + rpath[plen-1] = 'r'; + if (stat(rpath, &sb) == 0) { rc = 0; goto done; } /* success */ + if (!create) goto done; + + /* srmark file creation requested */ + umask(0); /* really want others to be able to write the srmark file */ + if ( (fd=open(rpath, O_WRONLY|O_CREAT|O_EXCL, 0766)) == -1) goto done; + if (flock(fd, LOCK_EX|LOCK_NB) == -1) goto done; + lseek(fd,0,SEEK_SET); + rp = strlen(KVSPOOL_MAGIC); + if (write(fd, &rp, sizeof(rp)) != sizeof(rp)) {unlink(rpath); goto done;} + rc = 0; + + done: + if (fd != -1) close(fd); + if (rpath) free(rpath); + return rc; +} + +/* attempt to open this file for writing and lock it */ +static int verify_and_lock(char *path, int create) { + int fd=-1; + struct stat sb; + int mode = O_RDWR|(create ? O_CREAT : 0); + + if (( (fd=open(path, mode, 0744)) == -1) || + (flock(fd, LOCK_EX|LOCK_NB) == -1) || + (fstat(fd, &sb) == -1) || + (has_spool_magic(fd,create) == -1) || + (has_srmark_file(path,create) == -1) || + (sb.st_size > kv_spool_options.file_max)) + { + if (fd != -1) { close(fd); fd=-1; } + goto done; + } + + if (sb.st_size) lseek(fd,-1*(sizeof(off_t)),SEEK_END); + + done: + return fd; +} + +static int lock_output_spool(const char *dir, const char *base, kv_spoolw_t *sp) { + int baselen = strlen(base); + char *name, *path, **p; + int fd = -1; + int ts,rnd; + DIR *d; + + UT_array *files; + utarray_new(files, &ut_str_icd); + UT_string *s; + utstring_new(s); + + sp_readdir(dir, base, ".sp", files); + sp_readlimits(dir); + sp_keep_maxseq(files); + p = NULL; + while ( (p = (char**)utarray_next(files,p))) { + path = *p; + fd = verify_and_lock(path,0); + if (fd != -1) goto done; // locked an existing spool; done + } + + /* need to make a new spool file. make a distinct name for it */ + ts = (int)time(NULL); + rnd = (((unsigned)(getpid()) & 0xf) << 4) | (rand() & 0xf); + utstring_clear(s); + utstring_printf(s,"%s/%s.%u.%.3u-0.sp", dir, base, ts, rnd); + path = utstring_body(s); + + if ( (fd=verify_and_lock(path,1)) == -1) { + fprintf(stderr, "failed to open output spool [%s]\n", path); + } + + done: + if (fd != -1) { + sp->fd = fd; + sp->path = strdup(path); + sp->base = strdup(base); + sp->dir = strdup(dir); + } + utarray_free(files); + utstring_free(s); + return fd; +} + +/* open a new file with an incremented sequence number. e.g., if the + * original is /tmp/myspool/spool.123456789.999-000.sp + * new one is /tmp/myspool/spool.123456789.999-001.sp +*/ +static int kv_spoolwriter_reopen(kv_spoolw_t *sp) { + assert(sp->path); + int fd, rc = -1, seq; + char *path, *hyph, *seqp; + + path = strdup(sp->path); + hyph = strrchr(path,'-'); if (!hyph) goto done; + seqp = hyph + 1; + if (sscanf(seqp, "%u", &seq) != 1) goto done; + seq++; + sprintf(seqp,"%u.sp", seq); + + if ( (fd = verify_and_lock(path,1)) == -1) goto done; + + /* success. store the new path and fd */ + free(sp->path); + if (sp->fd != -1) close(sp->fd); + sp->path = path; + sp->fd = fd; + sp->noc = 0; + rc = 0; + + done: + if (rc == -1) { + fprintf(stderr, "failed to re-open output spool [%s]\n", path); + free(path); + } + return rc; +} + + +/******************************************************************************* + * Spool writer API + ******************************************************************************/ +void *kv_spoolwriter_new(const char *dir, const char *base) { + assert(dir); assert(base); + + kv_spoolw_t *sp; + if ( (sp = malloc(sizeof(*sp))) == NULL) sp_oom(); + memset(sp,0,sizeof(*sp)); + sp->dir = NULL; + sp->base = NULL; + sp->path = NULL; + sp->fd = -1; + sp->noc = 0; /* schedule attrition scan for next write */ + + if (lock_output_spool(dir,base,sp) == -1) { free(sp); sp=NULL; } + return sp; +} + +/* check if one of the spools' files has reached its max size (reopen) + * or if the spool directory as a whole has reached its limit (attrition) */ +static void check_sizes(kv_spoolw_t *sp, int force_reopen) { + struct stat sb; + + if ( force_reopen || + (fstat(sp->fd, &sb) == -1) || + (sb.st_size > kv_spool_options.file_max)) kv_spoolwriter_reopen(sp); + + if (sb.st_size > sp->noc) { + sp_attrition(sp->dir); + sp->noc += (kv_spool_options.file_max / 2); + } +} + +/* used internally when kvsp-sub gets a serialized frame off network */ +int kv_write_raw_frame(void*_sp, void *img, size_t len) { + kv_spoolw_t *sp = (kv_spoolw_t*)_sp; assert(sp); + int rc = -1; + + if (write(sp->fd, img, len) != len) { + fprintf(stderr, "write to %s failed: %s\n", sp->path, strerror(errno)); + goto done; + } + rc = 0; + + done: + check_sizes(sp, rc); + return rc; +} + +int kv_spool_write(void*_sp, void *_set) { + kv_spoolw_t *sp = (kv_spoolw_t*)_sp; + kvset_t *set = (kvset_t*)_set; + tpl_node *tn = NULL; + char *buf=NULL; + char *key, fmt; + size_t len; + tpl_bin v; + int rc=-1; + + /* generate frame */ + tn = tpl_map("A(scB)", &key, &fmt, &v); + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + key = kv->key; + fmt = kv->fmt; + v.sz = kv->vlen; v.addr = kv->val; + tpl_pack(tn,1); + } + + tpl_dump(tn, TPL_MEM, &buf, &len); + if (buf==NULL || len==0) goto done; + if (write(sp->fd, buf, len) != len) goto done; + if (write(sp->fd, &len, sizeof(len)) != sizeof(len)) goto done; + lseek(sp->fd, -1*sizeof(len), SEEK_CUR); + rc=0; + + /* spool file and spool directory size check */ + done: + tpl_free(tn); + if (buf) free(buf); + check_sizes(sp, rc); + return rc; +} + +void kv_spoolwriter_free(void*_sp) { + assert(_sp); + kv_spoolw_t *sp = (kv_spoolw_t*)_sp; + if (sp->dir) free(sp->dir); + if (sp->base) free(sp->base); + if (sp->path) free(sp->path); + if (sp->fd != -1) close(sp->fd); + free(sp); +} + + diff --git a/sysutils/README b/sysutils/README new file mode 100644 index 0000000..9661956 --- /dev/null +++ b/sysutils/README @@ -0,0 +1,6 @@ +These utilities should eventually be moved out of the kvspool source tree. +They're here for now because they're sometimes useful with kvspool-based +applications, particularly pm and ramdisk. + +Note that pm (process manager) should be renamed because its name collides with +the kernel pm (power management) daemon. diff --git a/sysutils/logd/.gitignore b/sysutils/logd/.gitignore new file mode 100644 index 0000000..50a4edd --- /dev/null +++ b/sysutils/logd/.gitignore @@ -0,0 +1,6 @@ +TODO +liblogc.a +logc.o +logd/logd +tests/test1 +tests/test2 diff --git a/sysutils/logd/Makefile b/sysutils/logd/Makefile new file mode 100644 index 0000000..64cda72 --- /dev/null +++ b/sysutils/logd/Makefile @@ -0,0 +1,31 @@ +# the installed header and include files +LIB = liblogc.a +HDRS = logc.h + +SUBDIRS = logd +all: $(LIB) $(SUBDIRS) + +CFLAGS = -I. -fPIC -Ilogd +CFLAGS += -g +#CFLAGS += -O2 +SRCS = logc.c +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +$(LIB): $(SRCS) $(HDRS) + $(CC) $(CFLAGS) -c $(SRCS) + ar cr $@ $(OBJS) + + +.PHONY: clean $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +clean: + rm -f $(OBJS) $(LIB) + for f in $(SUBDIRS); do make -C $$f $@; done + +install: $(LIB) + cp $(LIB) /usr/local/lib + cp $(HDRS) /usr/local/include + for f in $(SUBDIRS); do make -C $$f $@; done diff --git a/sysutils/logd/README b/sysutils/logd/README new file mode 100644 index 0000000..05e2f25 --- /dev/null +++ b/sysutils/logd/README @@ -0,0 +1,14 @@ +This is a simple logging library. The premise of this library is that +there may be several separate binaries, each having multiple threads, +that should write to one or more logs. To prevent interleaving, we do +not just write to a common file descriptor (since multiple threads +would interleave their writes). Instead all logging is done by passing +the log messages through a named pipe (aka fifo) to a logd process. + +It is logd's job to read the fifo (whose contents will not be interleaved; +the fifo guarantees atomic writes up to PIPE_MAX bytes). Logd is a separate +process, so it must be running for logging to be effective (otherwise log +messages will be dropped or sent to syslog). + +The logd process also allows us to centrally configure logging destinations, +perform log file rotation, and so on. diff --git a/sysutils/logd/logc.c b/sysutils/logd/logc.c new file mode 100644 index 0000000..1a95330 --- /dev/null +++ b/sysutils/logd/logc.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "utstring.h" +#include "logc.h" +#include "logd.h" + +/* the program that links with this library should define + * the module name to something meaningful. it will cause + * a log file with that name to be written */ +extern char *modname; + +struct { + char *logd_fifo; + int logd_fd; + int on_tty; + int suppress_warning; +} cfg = { + .logd_fifo = LOGD_FIFO, + .logd_fd = -1, +}; + +int has_controlling_terminal(void) { + int fd; + fd = open("/dev/tty",O_RDONLY); + if (fd == -1) return 0; + close(fd); + return 1; +} + +#define LOGC_MSGMAX ((PIPE_BUF <= 0xffff) ? (PIPE_BUF-2) : (0xffff-2)) +void write_to_logd(UT_string *s,int prefix_len) { + uint16_t len = (uint16_t)utstring_len(s); + char *msg = utstring_body(s); + int rc,td; + + /* is the logd fifo open for writing? if not try to open it*/ + if (cfg.logd_fd == -1) { + if (has_controlling_terminal) cfg.on_tty=1; + cfg.logd_fd = open(cfg.logd_fifo,O_WRONLY|O_NONBLOCK); + if (cfg.logd_fd == -1) { + if (!cfg.suppress_warning) { + syslog(LOG_LOCAL0|LOG_INFO,"logd not running"); + cfg.suppress_warning=1; + } + if (cfg.on_tty) fprintf(stderr, "%s\n", msg+prefix_len); + syslog(LOG_LOCAL0|LOG_INFO,"%s", msg); + return; + } + } + if (cfg.on_tty) fprintf(stderr, "%s\n", msg+prefix_len); + if (len > LOGC_MSGMAX) len = LOGC_MSGMAX; /* atomic write limit */ + memcpy(msg,&len,sizeof(uint16_t)); /* prepend message len (inclusive) */ + if ( (rc=write(cfg.logd_fd, msg, len)) != len) { + syslog(LOG_LOCAL0|LOG_ERR,"write to logd failed (%s)", ((rc==-1) ? + strerror(errno) : "partial write")); + close(cfg.logd_fd); + cfg.logd_fd = -1; + } +} + +void lm(char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + + UT_string *s; + utstring_new(s); + + utstring_printf(s,"..%s|", modname?modname:""); + utstring_printf_va(s, fmt, ap); + write_to_logd(s,strlen(modname)+3); + + utstring_free(s); + va_end(ap); +} + diff --git a/sysutils/logd/logc.h b/sysutils/logd/logc.h new file mode 100644 index 0000000..ff419ac --- /dev/null +++ b/sysutils/logd/logc.h @@ -0,0 +1,9 @@ +#ifndef _LOGC_H_ +#define _LOGC_H_ + +void lm(char *fmt, ...); +#ifdef DEBUG +#define lmd lm +#endif //DEBUG + +#endif //_LOGC_H_ diff --git a/sysutils/logd/logd/Makefile b/sysutils/logd/logd/Makefile new file mode 100644 index 0000000..6d68a79 --- /dev/null +++ b/sysutils/logd/logd/Makefile @@ -0,0 +1,18 @@ +CFLAGS=-I.. +CFLAGS += -g + +BIN=logd +all: $(BIN) + +HDRS = logd.h +SRCS = logd.c +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +logd: $(SRCS) $(HDRS) + $(CC) $(CFLAGS) -o $@ $(SRCS) + +install: $(BIN) + cp $(BIN) /usr/local/bin + +clean: + rm -f logd *.o diff --git a/sysutils/logd/logd/logd.c b/sysutils/logd/logd/logd.c new file mode 100644 index 0000000..60df51b --- /dev/null +++ b/sysutils/logd/logd/logd.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "logd.h" +#include "uthash.h" + +#define DATETIME_FORMAT "%b %d %T " +#define DATETIME_MAXLEN 50 +#define LOGD_MAXSZ (1024 * 1024) /* 1 mb */ +#define MAINTENANCE_INTERVAL 10000 /* check log size every n lines */ + +struct { + char *log_dir; + int nmsgs; + int verbose; +} cfg = { + .log_dir = "/var/log/local", +}; + +/* we keep track of open log files with these */ +typedef struct { + int fd; + char *src; + int srclen; + UT_hash_handle hh; +} logfile_t; + +logfile_t *files = NULL; + +char buf[PIPE_BUF]; +char now[DATETIME_MAXLEN]; + +/* log messages are written to the fifo like "source|message". */ +int parse_msg(int len, char **src, int *srclen, char **msg, int *msglen) { + char *pipe = memchr(buf,'|',len); + if (!pipe) return -1; + + *src = buf; + *srclen = pipe-buf; + //*pipe = '\0'; + *msg = pipe+1; + *msglen = len - ((*msg)-buf); + return 0; +} + +int format_time(void) { + struct timeval now_tv; + time_t now_time; + struct tm *tm; + gettimeofday( &now_tv, NULL ); + now_time = (time_t)now_tv.tv_sec; + tm = localtime( &now_time ); + return strftime(now, DATETIME_MAXLEN, DATETIME_FORMAT, tm); +} + +int get_file(char *src,int srclen) { + + logfile_t *f; + HASH_FIND(hh, files, src, srclen, f); + if (f) return f->fd; + //printf("cache miss\n"); + + int fd = -1; + char *path; + UT_string *s; + utstring_new(s); + utstring_printf(s,"%s/%.*s.log", cfg.log_dir, srclen, src); + path = utstring_body(s); + + fd = open(path,O_WRONLY|O_APPEND|O_CREAT, 0644); + if (fd == -1) { + syslog(LOG_ERR,"can't open %s: %s", path, strerror(errno)); + } else { + f = malloc(sizeof(*f)); + f->src = strndup(src,srclen); + f->srclen = srclen; + f->fd = fd; + HASH_ADD_KEYPTR(hh, files, f->src, f->srclen, f); + } + + utstring_free(s); + return fd; +} + +void do_log(int len) { + char *src, *msg, *m; + int srclen, msglen, dtlen, fd; + + if (parse_msg(len,&src,&srclen,&msg,&msglen) == -1) { + syslog(LOG_ERR,"malformed message received"); + return; + } + + if ( (fd = get_file(src,srclen)) == -1) { + syslog(LOG_INFO,"%.*s",len,buf); + return; + } + + dtlen = format_time(); + m = msg; + while(m-msg < msglen) { + if (*m == '\n') { + write(fd, now, dtlen); + write(fd, msg, m-msg+1); + msglen -= (m-msg+1); + msg = m+1; + } else if (m-msg == msglen-1) { + write(fd, now, dtlen); + write(fd, msg, msglen); + write(fd, "\n", 1); + } + m++; + } +} + +/* check if any open log(s) need to be rolled and roll them */ +void roll_log(void) { + struct stat sb; + UT_string *s=NULL, *t=NULL; + char *oldpath, *newpath, *cmd; + logfile_t *f,*tmp; + + HASH_ITER(hh, files, f, tmp) { + if ((fstat(f->fd, &sb) == 0) && (sb.st_size < LOGD_MAXSZ)) continue; + + utstring_renew(s); + utstring_renew(t); + + /* rotate x.log to x.log.0. we only keep one rotated log for now */ + utstring_printf(s, "%s/%s.log", cfg.log_dir, f->src); + utstring_printf(t, "%s/%s.log.0", cfg.log_dir, f->src); + oldpath = utstring_body(s); + newpath = utstring_body(t); + unlink(newpath); /* blow away old .0, if it exists */ + if (link(oldpath, newpath) == -1) { + syslog(LOG_ERR, "link %s failed: %s", newpath, strerror(errno)); + } + if (unlink(oldpath) == -1) { + syslog(LOG_ERR, "unlink %s failed: %s", oldpath, strerror(errno)); + } + + HASH_DEL(files,f); + close(f->fd); + free(f->src); + free(f); + } + if (s) utstring_free(s); + if (t) utstring_free(t); +} + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-d ] [-v]\n", prog); + exit(-1); +} + +int main(int argc, char *argv[]) { + int opt, rc, fd=-1; + uint16_t msglen, bytes_read, bytes_left; + DIR *d; + + openlog("logd",LOG_PID,LOG_LOCAL0); + + while ( (opt = getopt(argc, argv, "d:v+")) != -1) { + switch (opt) { + case 'v': cfg.verbose++; break; + case 'd': cfg.log_dir = strdup(optarg); break; + default: usage(argv[0]); break; + } + } + + /* ensure the logs directory exists */ + if ( (!(d=opendir(cfg.log_dir))) && (mkdir(cfg.log_dir, 0755) == -1)) { + syslog(LOG_ERR, "can't create %s: %s", cfg.log_dir, strerror(errno)); + exit(-1); + } + closedir(d); + + /* create the fifo, ok if it already exists */ + rc = mkfifo(LOGD_FIFO, 0622); + if ((rc == -1) && (errno != EEXIST)) { + syslog(LOG_ERR, "can't create %s: %s", LOGD_FIFO, strerror(errno)); + exit(-1); + } + + /* open the fifo for reading */ + reopen: + if (fd != -1) close(fd); + fd = open(LOGD_FIFO, O_RDONLY); + if (fd == -1) { + syslog(LOG_ERR, "can't open %s: %s", LOGD_FIFO, strerror(errno)); + exit(-1); + } + + while (1) { + rc = read(fd, &msglen, sizeof(msglen)); /* read length prefix */ + if (rc == 0) goto reopen; /* last writer closed fifo, wait for new */ + else if ((rc == -1) && (errno == EINTR)) continue; /* signal */ + else if ((rc == -1) && (errno != EINTR)) { + syslog(LOG_ERR, "can't read %s: %s", LOGD_FIFO, strerror(errno)); + goto reopen; + } + else if (rc != sizeof(msglen)) goto reopen;/* can't read two bytes? */ + else if (rc == sizeof(msglen)) { + if ((msglen < 2) || (msglen > sizeof(buf))) goto reopen;/* sanity */ + msglen -= sizeof(msglen); /* subtract prefix len from message len */ + } + bytes_read = 0; + bytes_left = msglen; + while(bytes_left) { + rc = read(fd, &buf[bytes_read], bytes_left); + if (rc == 0) goto reopen; /* malformed, partial message then eof */ + else if (rc == -1 && errno != EINTR) { + syslog(LOG_ERR, "can't read %s: %s", LOGD_FIFO, strerror(errno)); + goto reopen; + } else if (rc > 0) { bytes_read += rc; bytes_left -= rc; } + } + + if (bytes_read == 0) continue; + do_log(bytes_read); + if ((cfg.nmsgs++ % MAINTENANCE_INTERVAL) == 0) roll_log(); + } +} diff --git a/sysutils/logd/logd/logd.h b/sysutils/logd/logd/logd.h new file mode 100644 index 0000000..b833a2b --- /dev/null +++ b/sysutils/logd/logd/logd.h @@ -0,0 +1,8 @@ +#ifndef _LOGD_H_ +#define _LOGD_H_ + +#include "utstring.h" + +#define LOGD_FIFO "/var/log/.logd" + +#endif //_LOGD_H_ diff --git a/sysutils/logd/tests/Makefile b/sysutils/logd/tests/Makefile new file mode 100644 index 0000000..486e86c --- /dev/null +++ b/sysutils/logd/tests/Makefile @@ -0,0 +1,12 @@ +CFLAGS=-I.. +CFLAGS+=-g +LDFLAGS=-L.. +LIBS=-llogc + +all: test1 test2 + +test1: test1.c ../liblogc.a + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + +test2: test2.c ../liblogc.a + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) diff --git a/sysutils/logd/tests/README b/sysutils/logd/tests/README new file mode 100644 index 0000000..b99f756 --- /dev/null +++ b/sysutils/logd/tests/README @@ -0,0 +1,2 @@ +test1: writes n log messages, can be used to test log rotation +test2: test atomicity of writes when parent/child both write logs diff --git a/sysutils/logd/tests/test1.c b/sysutils/logd/tests/test1.c new file mode 100644 index 0000000..d279ada --- /dev/null +++ b/sysutils/logd/tests/test1.c @@ -0,0 +1,7 @@ +#include "logc.h" +const char *modname = "test1"; +int main(int argc, char *argv[]) { + int iter=1; + if (argc > 1) iter = atoi(argv[1]); + while(iter--) lm("hello %d from %s", iter, argv[0]); +} diff --git a/sysutils/logd/tests/test2.c b/sysutils/logd/tests/test2.c new file mode 100644 index 0000000..158f468 --- /dev/null +++ b/sysutils/logd/tests/test2.c @@ -0,0 +1,8 @@ +#include "logc.h" +char *modname = "test2"; +int main(int argc, char *argv[]) { + char *who = (fork()) ? "parent" : "child"; + int iter=1; + if (argc > 1) iter = atoi(argv[1]); + while(iter--) lm("hello %d from %s", iter, who); +} diff --git a/sysutils/logd/uthash.h b/sysutils/logd/uthash.h new file mode 100644 index 0000000..e7fb5b7 --- /dev/null +++ b/sysutils/logd/uthash.h @@ -0,0 +1,973 @@ +/* +Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.3 + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + (head)->hh.tbl->signature = 0; \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * So MurmurHash comes in two versions, the faster unaligned one and the slower + * aligned one. We only use the faster one on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define HASH_MUR HASH_MUR_UNALIGNED +#else +#define HASH_MUR HASH_MUR_ALIGNED +#endif + +/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ +#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const unsigned int _mur_m = 0x5bd1e995; \ + const int _mur_r = 24; \ + hashv = 0xcafebabe ^ keylen; \ + char *_mur_key = (char *)(key); \ + uint32_t _mur_tmp, _mur_len = keylen; \ + \ + for (;_mur_len >= 4; _mur_len-=4) { \ + _mur_tmp = *(uint32_t *)_mur_key; \ + _mur_tmp *= _mur_m; \ + _mur_tmp ^= _mur_tmp >> _mur_r; \ + _mur_tmp *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_tmp; \ + _mur_key += 4; \ + } \ + \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + }; \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ +#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const unsigned int _mur_m = 0x5bd1e995; \ + const int _mur_r = 24; \ + hashv = 0xcafebabe ^ (keylen); \ + char *_mur_key = (char *)(key); \ + uint32_t _mur_len = keylen; \ + int _mur_align = (int)_mur_key & 3; \ + \ + if (_mur_align && (_mur_len >= 4)) { \ + unsigned _mur_t = 0, _mur_d = 0; \ + switch(_mur_align) { \ + case 1: _mur_t |= _mur_key[2] << 16; \ + case 2: _mur_t |= _mur_key[1] << 8; \ + case 3: _mur_t |= _mur_key[0]; \ + } \ + _mur_t <<= (8 * _mur_align); \ + _mur_key += 4-_mur_align; \ + _mur_len -= 4-_mur_align; \ + int _mur_sl = 8 * (4-_mur_align); \ + int _mur_sr = 8 * _mur_align; \ + \ + for (;_mur_len >= 4; _mur_len-=4) { \ + _mur_d = *(unsigned *)_mur_key; \ + _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + unsigned _mur_k = _mur_t; \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_t = _mur_d; \ + _mur_key += 4; \ + } \ + _mur_d = 0; \ + if(_mur_len >= _mur_align) { \ + switch(_mur_align) { \ + case 3: _mur_d |= _mur_key[2] << 16; \ + case 2: _mur_d |= _mur_key[1] << 8; \ + case 1: _mur_d |= _mur_key[0]; \ + } \ + unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_k += _mur_align; \ + _mur_len -= _mur_align; \ + \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + } \ + } else { \ + switch(_mur_len) \ + { \ + case 3: _mur_d ^= _mur_key[2] << 16; \ + case 2: _mur_d ^= _mur_key[1] << 8; \ + case 1: _mur_d ^= _mur_key[0]; \ + case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ + hashv *= _mur_m; \ + } \ + } \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + } else { \ + for (;_mur_len >= 4; _mur_len-=4) { \ + unsigned _mur_k = *(unsigned*)_mur_key; \ + _mur_k *= _mur_m; \ + _mur_k ^= _mur_k >> _mur_r; \ + _mur_k *= _mur_m; \ + hashv *= _mur_m; \ + hashv ^= _mur_k; \ + _mur_key += 4; \ + } \ + switch(_mur_len) \ + { \ + case 3: hashv ^= _mur_key[2] << 16; \ + case 2: hashv ^= _mur_key[1] << 8; \ + case 1: hashv ^= _mur_key[0]; \ + hashv *= _mur_m; \ + } \ + \ + hashv ^= hashv >> 13; \ + hashv *= _mur_m; \ + hashv ^= hashv >> 15; \ + } \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/sysutils/logd/utstring.h b/sysutils/logd/utstring.h new file mode 100644 index 0000000..c8b4569 --- /dev/null +++ b/sysutils/logd/utstring.h @@ -0,0 +1,146 @@ +/* +Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + * see http://uthash.sourceforge.net/utstring + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.1 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve(s,(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + s->i += l; \ + s->d[s->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve(dst,(src->i)+1); \ + if (src->i) memcpy(&(dst)->d[(dst)->i], src->d, src->i); \ + dst->i += src->i; \ + dst->d[dst->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && (n < (int)(s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +#endif /* UTSTRING_H */ diff --git a/sysutils/pm/.gitignore b/sysutils/pm/.gitignore new file mode 100644 index 0000000..cdef01b --- /dev/null +++ b/sysutils/pm/.gitignore @@ -0,0 +1,6 @@ +lemon/lemon +pm +dm +cfg.c +cfg.h +cfg.out diff --git a/sysutils/pm/Makefile b/sysutils/pm/Makefile new file mode 100644 index 0000000..13b87a6 --- /dev/null +++ b/sysutils/pm/Makefile @@ -0,0 +1,25 @@ +SUBDIRS=lemon +all: $(SUBDIRS) pm +CFLAGS=-I /usr/local/include +CFLAGS+=-g + + +.PHONY: clean $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +cfg.c: cfg.y + lemon/lemon $< + +pm: pm.c cfg.c job.c tok.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + rm -f *.o *.out pm cfg.c cfg.h + for f in $(SUBDIRS); do make -C $$f $@; done + +install: pm + cp $^ /usr/local/bin + cp upstart/pm.conf /etc/init/pm.conf + touch /etc/pm.conf diff --git a/sysutils/pm/cfg.y b/sysutils/pm/cfg.y new file mode 100644 index 0000000..1467aa2 --- /dev/null +++ b/sysutils/pm/cfg.y @@ -0,0 +1,41 @@ +%include {#include } +%include {#include } +%include {#include } +%include {#include "job.h"} +%include {#include "utarray.h"} +%token_prefix TOK_ +%token_type {char*} +%extra_argument {parse_t *ps} +%syntax_error { + utstring_printf(ps->em, "error in %s line %d ", ps->file, ps->line); + ps->rc=-1; +} +%parse_failure {ps->rc=-1;} +%type path {char*} +%type arg {char*} + +file ::= jobs. +file ::= . +jobs ::= jobs job. +jobs ::= job. +job ::= JOB LCURLY sbody RCURLY. {push_job(ps);} +sbody ::= sbody kv. +sbody ::= kv. +kv ::= NAME STR(A). {set_name(ps,A);} +kv ::= CMD cmd. +kv ::= DIR path(A). {set_dir(ps,A);} +kv ::= OUT path(A). {set_out(ps,A);} +kv ::= ERR path(A). {set_err(ps,A);} +kv ::= USER STR(A). {set_usr(ps,A);} +kv ::= ORDER STR(A). {set_ord(ps,A);} +kv ::= ENV STR(A). {set_env(ps,A);} +kv ::= DISABLED. {set_dis(ps); } +kv ::= WAIT. {set_wait(ps); } +kv ::= ONCE. {set_once(ps); } +cmd ::= path(A). {set_cmd(ps,A);} +cmd ::= path(A) args. {set_cmd(ps,A);} +path(A) ::= STR(B). {A=B;} +args ::= args arg(B). {utarray_push_back(&ps->job->cmdv,&B);} +args ::= arg(B). {utarray_push_back(&ps->job->cmdv,&B);} +arg(A) ::= STR(B). {A=B;} +arg(A) ::= QUOTEDSTR(B). {A=unquote(B);} diff --git a/sysutils/pm/job.c b/sysutils/pm/job.c new file mode 100644 index 0000000..458f510 --- /dev/null +++ b/sysutils/pm/job.c @@ -0,0 +1,393 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG 1 + +#include "utarray.h" +#include "job.h" + + +/* lemon prototypes */ +void *ParseAlloc(); +void Parse(); +void ParseFree(); + +static void job_ini(job_t *job) { + memset(job,0,sizeof(*job)); + utarray_init(&job->cmdv, &ut_str_icd); + utarray_init(&job->envv, &ut_str_icd); + job->respawn=1; + job->uid=-1; +} +static void job_fin(job_t *job) { + if (job->name) free(job->name); + utarray_done(&job->cmdv); + utarray_done(&job->envv); + if (job->dir) free(job->dir); + if (job->out) free(job->out); + if (job->err) free(job->err); + if (job->usr) free(job->usr); +} +static void job_cpy(job_t *dst, const job_t *src) { + dst->name = src->name ? strdup(src->name) : NULL; + utarray_init(&dst->cmdv, &ut_str_icd); utarray_concat(&dst->cmdv, &src->cmdv); + utarray_init(&dst->envv, &ut_str_icd); utarray_concat(&dst->envv, &src->envv); + dst->dir = src->dir ? strdup(src->dir) : NULL; + dst->out = src->out ? strdup(src->out) : NULL; + dst->err = src->err ? strdup(src->err) : NULL; + dst->usr = src->usr ? strdup(src->usr) : NULL; + dst->uid = src->uid; + dst->pid = src->pid; + dst->start_ts = src->start_ts; + dst->respawn = src->respawn; + dst->order = src->order; + dst->disabled = src->disabled; + dst->wait = src->wait; + dst->once = src->once; +} +const UT_icd job_mm={sizeof(job_t), (init_f*)job_ini, + (ctor_f*)job_cpy, (dtor_f*)job_fin }; + +/* these "set_" functions are called from the lemon-generated parser. they + * indicate an error by setting ps->rc to -1. the values they set are one of + * the fields in ps->job. */ +#define mk_setter(n) \ +void set_ ## n(parse_t *ps, char *v) { \ + if (ps->job->n) { \ + utstring_printf(ps->em, #n " respecified near line %d in %s ", \ + ps->line, ps->file); \ + ps->rc = -1; \ + return; \ + } \ + ps->job->n = strdup(v); \ +} +mk_setter(name); +mk_setter(dir); +mk_setter(out); +mk_setter(err); +mk_setter(usr); +void set_cmd(parse_t *ps, char *cmd) { + utarray_insert(&ps->job->cmdv,&cmd,0); +} +void set_env(parse_t *ps, char *env) { + if (strchr(env,'=') == NULL) { + utstring_printf(ps->em, "environment string must be VAR=VALUE"); + ps->rc = -1; + return; + } + utarray_push_back(&ps->job->envv,&env); +} +void set_ord(parse_t *ps, char *ord) { + if (sscanf(ord,"%d",&ps->job->order) != 1) { + utstring_printf(ps->em, "non-numeric order parameter"); + ps->rc = -1; + } +} +void set_dis(parse_t *ps) { ps->job->disabled = 1; } +void set_wait(parse_t *ps) { ps->job->wait = 1; } +void set_once(parse_t *ps) { ps->job->once = 1; } +void push_job(parse_t *ps) { + struct passwd *p; + utarray_extend_back(&ps->job->cmdv); /* put NULL on end of argv */ + utarray_push_back(ps->jobs, ps->job); + /* convert user id to uid */ + if (ps->job->usr) { + if ( (p = getpwnam(ps->job->usr)) == NULL) { + utstring_printf(ps->em, "cannot find uid for user %s", ps->job->usr); + ps->rc = -1; + } else { + ps->job->uid = p->pw_uid; + } + } + if (!ps->job->name) { + utstring_printf(ps->em, "job has no name"); + ps->rc = -1; + } + /* reset job for another parse */ + if (ps->rc != -1) { + job_fin(ps->job); + job_ini(ps->job); + } +} +char *unquote(char *str) { + assert(*str == '"'); + char *q = strchr(str+1,'"'); + assert(q); + *q = '\0'; + return str+1; +} + +/* this function reads a whole file into a malloc'd buffer */ +char *slurp(char *file, size_t *len) { + struct stat s; + char *buf; + int fd; + if (stat(file, &s) == -1) { + fprintf(stderr,"can't stat %s: %s\n", file, strerror(errno)); + exit(-1); + } + *len = s.st_size; + if ( (fd = open(file, O_RDONLY)) == -1) { + fprintf(stderr,"can't open %s: %s\n", file, strerror(errno)); + exit(-1); + } + buf = malloc(*len); + if (buf) { + if (read(fd, buf,*len) != *len) { + fprintf(stderr,"incomplete read\n"); + exit(-1); + } + } + close(fd); + return buf; +} + +static int order_sort(const void *_a, const void *_b) { + job_t *a = (job_t*)_a, *b = (job_t*)_b; + return a->order - b->order; +} +int parse_jobs(UT_array *jobs, UT_string *em, char *file, int verbose) { + char *buf, *c, *tok; + size_t len,toklen; + UT_array *toks; + parse_t ps; /* our own parser state */ + void *p; /* lemon parser */ + int id; + + utarray_new(toks,&ut_str_icd); + job_t job; /* "scratch" space used when parsing a job */ + job_ini(&job); + + ps.line=1; ps.rc=0; ps.file=file; ps.em=em, ps.job=&job; ps.jobs=jobs; + p = ParseAlloc(malloc); + + buf = slurp(file, &len); + c = buf; + while ( (id=get_tok(buf,&c,&len,&toklen,&ps.line)) > 0) { + tok = strndup(c,toklen); utarray_push_back(toks,&tok); free(tok); + tok = *(char**)utarray_back(toks); + if (verbose >= 2) printf("got token [%s] id=%d line=%d\n",tok, id, ps.line); + Parse(p, id, tok, &ps); + if (ps.rc == -1) goto done; + len -= toklen; + c += toklen; + } + if (id == -1) { + utstring_printf(em,"tokenizer error in %s line %d\n", ps.file, ps.line); + ps.rc = -1; + goto done; + } + Parse(p, 0, NULL, &ps); + if (ps.rc == -1) goto done; + + /* parsing succeeded */ + utarray_sort(jobs, order_sort); + + done: + utarray_free(toks); + ParseFree(p, free); + free(buf); + job_fin(&job); + return ps.rc; +} + +/* start up the jobs that are not already running */ +void do_jobs(UT_array *jobs) { + pid_t pid; + int es, n, fo, fe, fi; + char *pathname, *o, *e, **argv, **env; + + job_t *job = NULL; + while ( (job = (job_t*)utarray_next(jobs,job))) { + if (job->disabled) continue; + if (job->pid) continue; /* running already */ + if (job->respawn == 0) continue; /* don't respawn */ + + if ( (pid = fork()) == -1) { + syslog(LOG_ERR,"fork error\n"); + kill(getpid(), 15); /* induce graceful shutdown in main loop */ + return; + } + + if (pid > 0) { /* parent */ + job->pid = pid; + job->start_ts = time(NULL); + syslog(LOG_INFO,"started job %s [%d]", job->name, (int)job->pid); + /* support the 'wait' feature which pauses (blocks) for a job to finish. + * this is most likely useful with 'order 0' to do some pre-init work. */ + if (job->wait) { + syslog(LOG_INFO,"pausing for job %s to finish",job->name); + if (waitpid(job->pid, &es, 0) != job->pid) { + syslog(LOG_ERR,"waitpid for job %s failed\n",job->name); + continue; + } + syslog(LOG_INFO,"job %s finished",job->name); + if (WIFEXITED(es) && (WEXITSTATUS(es) == PM_NO_RESTART)) job->respawn=0; + else if (job->once) job->respawn=0; + job->pid = 0; + } + continue; + } + + /********************************************************************* + * child here + ********************************************************************/ + assert(pid == 0); + if (job->dir && (chdir(job->dir) == -1)) { + syslog(LOG_ERR,"cannot chdir: %s\n", strerror(errno)); goto fail; + } + /* setup child stdout/stderr */ + o = job->out ? job->out : "/dev/null"; + e = job->err ? job->err : "/dev/null"; + if ( (fo = open(o, O_WRONLY|O_APPEND|O_CREAT, 0644)) == -1) { + syslog(LOG_ERR,"cannot open %s: %s\n", o, strerror(errno)); goto fail; + } + if ( (fe = open(e, O_WRONLY|O_APPEND|O_CREAT, 0644)) == -1) { + syslog(LOG_ERR,"cannot open %s: %s\n", e, strerror(errno)); goto fail; + } + if (dup2(fo,STDOUT_FILENO) == -1) { + syslog(LOG_ERR,"cannot dup %s to stdout: %s\n", o, strerror(errno)); goto fail; + } + if (dup2(fe,STDERR_FILENO) == -1) { + syslog(LOG_ERR,"cannot dup %s to stderr: %s\n", e, strerror(errno)); goto fail; + } + if ( (fi = open("/dev/null", O_RDONLY)) == -1) { + syslog(LOG_ERR,"cannot open /dev/null: %s\n", strerror(errno)); goto fail; + } + if (dup2(fi,STDIN_FILENO) == -1) { + syslog(LOG_ERR,"cannot dup /dev/null to stdin: %s\n", strerror(errno)); goto fail; + } + + /* set environment variables */ + env=NULL; + while ( (env=(char**)utarray_next(&job->envv,env))) putenv(*env); + + /* restore/unblock default handlers so they're unblocked after exec */ + for(n=0; n < sizeof(sigs)/sizeof(*sigs); n++) signal(sigs[n], SIG_DFL); + sigset_t none; + sigemptyset(&none); + sigprocmask(SIG_SETMASK,&none,NULL); + + /* at last. we're ready to run the child process */ + if ((job->uid != -1) && (geteuid() != job->uid)) { + if (setuid(job->uid) == -1) { + syslog(LOG_ERR,"setuid failed: %s\n", strerror(errno)); + goto fail; + } + } + argv = (char**)utarray_front(&job->cmdv); + pathname = *argv; + if (execv(pathname, argv) == -1) { + syslog(LOG_ERR,"exec failed: %s\n", strerror(errno)); goto fail; + } + assert(0); /* not reached - child has exec'd */ + + fail: + exit(-1); /* child exit on failure to exec */ + } +} + +int term_job(job_t *job) { + int es,rc=-1; + + UT_string *s; + utstring_new(s); + utstring_printf(s,"job %s [%d]: ", job->name, (int)job->pid); + + if (job->pid == 0) return; /* not running */ + kill(job->pid, SIGTERM); + if (waitpid(job->pid, &es, WNOHANG) == job->pid) job->pid = 0; + else { /* child didn't exit. give it a moment, then force quit. */ + sleep(1); + kill(job->pid, SIGKILL); + if (waitpid(job->pid, &es, WNOHANG) == job->pid) job->pid = 0; + else { + utstring_printf(s, "failed to terminate"); + goto done; + } + } + rc = 0; /* success */ + if (WIFSIGNALED(es)) utstring_printf(s,"exited on signal %d", (int)WTERMSIG(es)); + else if (WIFEXITED(es)) utstring_printf(s,"exit status %d", (int)WEXITSTATUS(es)); + + done: + syslog(rc==-1?LOG_ERR:LOG_INFO, "%s", utstring_body(s)); + utstring_free(s); + return rc; +} + +void term_jobs(UT_array *jobs) { + job_t *job = NULL; + while ( (job = (job_t*)utarray_next(jobs,job))) term_job(job); +} + +job_t *get_job_by_pid(UT_array *jobs, pid_t pid) { + job_t *job = NULL; + while ( (job = (job_t*)utarray_next(jobs,job))) { + if (job->pid == pid) return job; + } + return NULL; +} + +job_t *get_job_by_name(UT_array *jobs, char *name) { + job_t *job = NULL; + while ( (job = (job_t*)utarray_next(jobs,job))) { + if (!strcmp(job->name,name)) return job; + } + return NULL; +} + +/* this comparison function is used to see if two job _definitions_ (not + * running instances) are equal. it is used when rescanning the config file */ +int job_cmp(job_t *a, job_t *b) { + char **ac,**bc; + int rc, alen, blen; + if ( (rc=strcmp(a->name,b->name)) != 0) return rc; + /* compare cmdv */ + alen = utarray_len(&a->cmdv); blen = utarray_len(&b->cmdv); + if (alen != blen) return alen-blen; + ac=NULL; bc=NULL; + while ( (ac=(char**)utarray_next(&a->cmdv,ac))) { + bc = (char**)utarray_next(&b->cmdv,bc); + if ((*ac && *bc) && ((rc=strcmp(*ac,*bc)) != 0)) return rc; + } + /* compare envv */ + alen = utarray_len(&a->envv); blen = utarray_len(&b->envv); + if (alen != blen) return alen-blen; + ac=NULL; bc=NULL; + while ( (ac=(char**)utarray_next(&a->envv,ac))) { + bc = (char**)utarray_next(&b->envv,bc); + if ((*ac && *bc) && ((rc=strcmp(*ac,*bc)) != 0)) return rc; + } + /* dir */ + if ((!a->dir && b->dir) || (a->dir && !b->dir) ) return a->dir-b->dir; + if ((a->dir && b->dir) && (rc = strcmp(a->dir,b->dir))) return rc; + /* out */ + if ((!a->out && b->out) || (a->out && !b->out) ) return a->out-b->out; + if ((a->out && b->out) && (rc = strcmp(a->out,b->out))) return rc; + /* err */ + if ((!a->err && b->err) || (a->err && !b->err) ) return a->err-b->err; + if ((a->err && b->err) && (rc = strcmp(a->err,b->err))) return rc; + /* usr (username) */ + if ((!a->usr && b->usr) || (a->usr && !b->usr) ) return a->usr-b->usr; + if ((a->usr && b->usr) && (rc = strcmp(a->usr,b->usr))) return rc; + + if (a->uid != b->uid) return a->uid - b->uid; + if (a->order != b->order) return a->order - b->order; + if (a->disabled != b->disabled) return a->disabled - b->disabled; + if (a->wait != b->wait) return a->wait - b->wait; + if (a->once != b->once) return a->once - b->once; + return 0; +} + diff --git a/sysutils/pm/job.h b/sysutils/pm/job.h new file mode 100644 index 0000000..e8e6f5d --- /dev/null +++ b/sysutils/pm/job.h @@ -0,0 +1,61 @@ +#ifndef _JOB_H_ +#define _JOB_H_ + +#include +#include +#include +#include + +#include "utstring.h" +#include "utarray.h" + +/* exit status that a job can use to indicate it does not want to be respawned */ +#define PM_NO_RESTART 33 + +/* signals that we'll allow (unblock) during sigsuspend */ +static const int sigs[] = {SIGHUP,SIGCHLD,SIGTERM,SIGINT,SIGQUIT,SIGALRM,SIGUSR1}; + +typedef struct { + char *name; + UT_array cmdv; + UT_array envv; + char *dir; + char *out; + char *err; + pid_t pid; + time_t start_ts; + char *usr; + uid_t uid; + int respawn; + int order; + int disabled; + int wait; + int once; + /* remember to edit job_cmp in job.c if equality definition needs updating */ +} job_t; + +typedef struct { + int line; + char *file; + int rc; + UT_string *em; + job_t *job; /* scratch space */ + UT_array *jobs; +} parse_t; + +extern const UT_icd job_mm; + +/* prototypes */ +int parse_jobs(UT_array *jobs, UT_string *em, char *file, int verbose); +void do_jobs(UT_array *jobs); +void term_jobs(UT_array *jobs); +int term_job(job_t *job); +void push_job(parse_t *ps); +job_t *get_job_by_pid(UT_array *jobs, pid_t pid); +job_t *get_job_by_name(UT_array *jobs, char *name); +int job_cmp(job_t *a, job_t *b); +void set_name(parse_t *ps, char *name); +char *unquote(char *str); + + +#endif /* _JOB_H_ */ diff --git a/sysutils/pm/lemon/Makefile b/sysutils/pm/lemon/Makefile new file mode 100644 index 0000000..df59bcb --- /dev/null +++ b/sysutils/pm/lemon/Makefile @@ -0,0 +1,9 @@ +CFLAGS = -Wall +CFLAGS += -g + +all: lemon + +lemon: lemon.c + +clean: + rm -f lemon *.o diff --git a/sysutils/pm/lemon/lemon.c b/sysutils/pm/lemon/lemon.c new file mode 100644 index 0000000..8336e9a --- /dev/null +++ b/sysutils/pm/lemon/lemon.c @@ -0,0 +1,4889 @@ +/* +** This file contains all sources (including headers) to the LEMON +** LALR(1) parser generator. The sources have been combined into a +** single file to make it easy to include LEMON in the source tree +** and Makefile of another program. +** +** The author of this program disclaims copyright. +*/ +#include +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +# if defined(_WIN32) || defined(WIN32) +# define __WIN32__ +# endif +#endif + +#ifdef __WIN32__ +extern int access(); +#else +#include +#endif + +/* #define PRIVATE static */ +#define PRIVATE + +#ifdef TEST +#define MAXRHS 5 /* Set low to exercise exception code */ +#else +#define MAXRHS 1000 +#endif + +static char *msort(char*,char**,int(*)(const char*,const char*)); + +/* +** Compilers are getting increasingly pedantic about type conversions +** as C evolves ever closer to Ada.... To work around the latest problems +** we have to define the following variant of strlen(). +*/ +#define lemonStrlen(X) ((int)strlen(X)) + +static struct action *Action_new(void); +static struct action *Action_sort(struct action *); + +/********** From the file "build.h" ************************************/ +void FindRulePrecedences(); +void FindFirstSets(); +void FindStates(); +void FindLinks(); +void FindFollowSets(); +void FindActions(); + +/********* From the file "configlist.h" *********************************/ +void Configlist_init(/* void */); +struct config *Configlist_add(/* struct rule *, int */); +struct config *Configlist_addbasis(/* struct rule *, int */); +void Configlist_closure(/* void */); +void Configlist_sort(/* void */); +void Configlist_sortbasis(/* void */); +struct config *Configlist_return(/* void */); +struct config *Configlist_basis(/* void */); +void Configlist_eat(/* struct config * */); +void Configlist_reset(/* void */); + +/********* From the file "error.h" ***************************************/ +void ErrorMsg(const char *, int,const char *, ...); + +/****** From the file "option.h" ******************************************/ +struct s_options { + enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, + OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type; + char *label; + char *arg; + char *message; +}; +int OptInit(/* char**,struct s_options*,FILE* */); +int OptNArgs(/* void */); +char *OptArg(/* int */); +void OptErr(/* int */); +void OptPrint(/* void */); + +/******** From the file "parse.h" *****************************************/ +void Parse(/* struct lemon *lemp */); + +/********* From the file "plink.h" ***************************************/ +struct plink *Plink_new(/* void */); +void Plink_add(/* struct plink **, struct config * */); +void Plink_copy(/* struct plink **, struct plink * */); +void Plink_delete(/* struct plink * */); + +/********** From the file "report.h" *************************************/ +void Reprint(/* struct lemon * */); +void ReportOutput(/* struct lemon * */); +void ReportTable(/* struct lemon * */); +void ReportHeader(/* struct lemon * */); +void CompressTables(/* struct lemon * */); +void ResortStates(/* struct lemon * */); + +/********** From the file "set.h" ****************************************/ +void SetSize(/* int N */); /* All sets will be of size N */ +char *SetNew(/* void */); /* A new set for element 0..N */ +void SetFree(/* char* */); /* Deallocate a set */ + +int SetAdd(/* char*,int */); /* Add element to a set */ +int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */ + +#define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ + +/********** From the file "struct.h" *************************************/ +/* +** Principal data structures for the LEMON parser generator. +*/ + +typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; + +/* Symbols (terminals and nonterminals) of the grammar are stored +** in the following: */ +struct symbol { + char *name; /* Name of the symbol */ + int index; /* Index number for this symbol */ + enum { + TERMINAL, + NONTERMINAL, + MULTITERMINAL + } type; /* Symbols are all either TERMINALS or NTs */ + struct rule *rule; /* Linked list of rules of this (if an NT) */ + struct symbol *fallback; /* fallback token in case this token doesn't parse */ + int prec; /* Precedence if defined (-1 otherwise) */ + enum e_assoc { + LEFT, + RIGHT, + NONE, + UNK + } assoc; /* Associativity if precedence is defined */ + char *firstset; /* First-set for all rules of this symbol */ + Boolean lambda; /* True if NT and can generate an empty string */ + int useCnt; /* Number of times used */ + char *destructor; /* Code which executes whenever this symbol is + ** popped from the stack during error processing */ + int destLineno; /* Line number for start of destructor */ + char *datatype; /* The data type of information held by this + ** object. Only used if type==NONTERMINAL */ + int dtnum; /* The data type number. In the parser, the value + ** stack is a union. The .yy%d element of this + ** union is the correct data type for this object */ + /* The following fields are used by MULTITERMINALs only */ + int nsubsym; /* Number of constituent symbols in the MULTI */ + struct symbol **subsym; /* Array of constituent symbols */ +}; + +/* Each production rule in the grammar is stored in the following +** structure. */ +struct rule { + struct symbol *lhs; /* Left-hand side of the rule */ + char *lhsalias; /* Alias for the LHS (NULL if none) */ + int lhsStart; /* True if left-hand side is the start symbol */ + int ruleline; /* Line number for the rule */ + int nrhs; /* Number of RHS symbols */ + struct symbol **rhs; /* The RHS symbols */ + char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ + int line; /* Line number at which code begins */ + char *code; /* The code executed when this rule is reduced */ + struct symbol *precsym; /* Precedence symbol for this rule */ + int index; /* An index number for this rule */ + Boolean canReduce; /* True if this rule is ever reduced */ + struct rule *nextlhs; /* Next rule with the same LHS */ + struct rule *next; /* Next rule in the global list */ +}; + +/* A configuration is a production rule of the grammar together with +** a mark (dot) showing how much of that rule has been processed so far. +** Configurations also contain a follow-set which is a list of terminal +** symbols which are allowed to immediately follow the end of the rule. +** Every configuration is recorded as an instance of the following: */ +struct config { + struct rule *rp; /* The rule upon which the configuration is based */ + int dot; /* The parse point */ + char *fws; /* Follow-set for this configuration only */ + struct plink *fplp; /* Follow-set forward propagation links */ + struct plink *bplp; /* Follow-set backwards propagation links */ + struct state *stp; /* Pointer to state which contains this */ + enum { + COMPLETE, /* The status is used during followset and */ + INCOMPLETE /* shift computations */ + } status; + struct config *next; /* Next configuration in the state */ + struct config *bp; /* The next basis configuration */ +}; + +/* Every shift or reduce operation is stored as one of the following */ +struct action { + struct symbol *sp; /* The look-ahead symbol */ + enum e_action { + SHIFT, + ACCEPT, + REDUCE, + ERROR, + SSCONFLICT, /* A shift/shift conflict */ + SRCONFLICT, /* Was a reduce, but part of a conflict */ + RRCONFLICT, /* Was a reduce, but part of a conflict */ + SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ + RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ + NOT_USED /* Deleted by compression */ + } type; + union { + struct state *stp; /* The new state, if a shift */ + struct rule *rp; /* The rule, if a reduce */ + } x; + struct action *next; /* Next action for this state */ + struct action *collide; /* Next action with the same hash */ +}; + +/* Each state of the generated parser's finite state machine +** is encoded as an instance of the following structure. */ +struct state { + struct config *bp; /* The basis configurations for this state */ + struct config *cfp; /* All configurations in this set */ + int statenum; /* Sequential number for this state */ + struct action *ap; /* Array of actions for this state */ + int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ + int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ + int iDflt; /* Default action */ +}; +#define NO_OFFSET (-2147483647) + +/* A followset propagation link indicates that the contents of one +** configuration followset should be propagated to another whenever +** the first changes. */ +struct plink { + struct config *cfp; /* The configuration to which linked */ + struct plink *next; /* The next propagate link */ +}; + +/* The state vector for the entire parser generator is recorded as +** follows. (LEMON uses no global variables and makes little use of +** static variables. Fields in the following structure can be thought +** of as begin global variables in the program.) */ +struct lemon { + struct state **sorted; /* Table of states sorted by state number */ + struct rule *rule; /* List of all rules */ + int nstate; /* Number of states */ + int nrule; /* Number of rules */ + int nsymbol; /* Number of terminal and nonterminal symbols */ + int nterminal; /* Number of terminal symbols */ + struct symbol **symbols; /* Sorted array of pointers to symbols */ + int errorcnt; /* Number of errors */ + struct symbol *errsym; /* The error symbol */ + struct symbol *wildcard; /* Token that matches anything */ + char *name; /* Name of the generated parser */ + char *arg; /* Declaration of the 3th argument to parser */ + char *tokentype; /* Type of terminal symbols in the parser stack */ + char *vartype; /* The default type of non-terminal symbols */ + char *start; /* Name of the start symbol for the grammar */ + char *stacksize; /* Size of the parser stack */ + char *include; /* Code to put at the start of the C file */ + char *error; /* Code to execute when an error is seen */ + char *overflow; /* Code to execute on a stack overflow */ + char *failure; /* Code to execute on parser failure */ + char *accept; /* Code to execute when the parser excepts */ + char *extracode; /* Code appended to the generated file */ + char *tokendest; /* Code to execute to destroy token data */ + char *vardest; /* Code for the default non-terminal destructor */ + char *filename; /* Name of the input file */ + char *outname; /* Name of the current output file */ + char *tokenprefix; /* A prefix added to token names in the .h file */ + int nconflict; /* Number of parsing conflicts */ + int tablesize; /* Size of the parse tables */ + int basisflag; /* Print only basis configurations */ + int has_fallback; /* True if any %fallback is seen in the grammar */ + int nolinenosflag; /* True if #line statements should not be printed */ + char *argv0; /* Name of the program */ +}; + +#define MemoryCheck(X) if((X)==0){ \ + extern void memory_error(); \ + memory_error(); \ +} + +/**************** From the file "table.h" *********************************/ +/* +** All code in this file has been automatically generated +** from a specification in the file +** "table.q" +** by the associative array code building program "aagen". +** Do not edit this file! Instead, edit the specification +** file, then rerun aagen. +*/ +/* +** Code for processing tables in the LEMON parser generator. +*/ + +/* Routines for handling a strings */ + +char *Strsafe(); + +void Strsafe_init(/* void */); +int Strsafe_insert(/* char * */); +char *Strsafe_find(/* char * */); + +/* Routines for handling symbols of the grammar */ + +struct symbol *Symbol_new(); +int Symbolcmpp(/* struct symbol **, struct symbol ** */); +void Symbol_init(/* void */); +int Symbol_insert(/* struct symbol *, char * */); +struct symbol *Symbol_find(/* char * */); +struct symbol *Symbol_Nth(/* int */); +int Symbol_count(/* */); +struct symbol **Symbol_arrayof(/* */); + +/* Routines to manage the state table */ + +int Configcmp(/* struct config *, struct config * */); +struct state *State_new(); +void State_init(/* void */); +int State_insert(/* struct state *, struct config * */); +struct state *State_find(/* struct config * */); +struct state **State_arrayof(/* */); + +/* Routines used for efficiency in Configlist_add */ + +void Configtable_init(/* void */); +int Configtable_insert(/* struct config * */); +struct config *Configtable_find(/* struct config * */); +void Configtable_clear(/* int(*)(struct config *) */); +/****************** From the file "action.c" *******************************/ +/* +** Routines processing parser actions in the LEMON parser generator. +*/ + +/* Allocate a new parser action */ +static struct action *Action_new(void){ + static struct action *freelist = 0; + struct action *new; + + if( freelist==0 ){ + int i; + int amt = 100; + freelist = (struct action *)calloc(amt, sizeof(struct action)); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new parser action."); + exit(1); + } + for(i=0; inext; + return new; +} + +/* Compare two actions for sorting purposes. Return negative, zero, or +** positive if the first action is less than, equal to, or greater than +** the first +*/ +static int actioncmp( + struct action *ap1, + struct action *ap2 +){ + int rc; + rc = ap1->sp->index - ap2->sp->index; + if( rc==0 ){ + rc = (int)ap1->type - (int)ap2->type; + } + if( rc==0 && ap1->type==REDUCE ){ + rc = ap1->x.rp->index - ap2->x.rp->index; + } + return rc; +} + +/* Sort parser actions */ +static struct action *Action_sort( + struct action *ap +){ + ap = (struct action *)msort((char *)ap,(char **)&ap->next, + (int(*)(const char*,const char*))actioncmp); + return ap; +} + +void Action_add(app,type,sp,arg) +struct action **app; +enum e_action type; +struct symbol *sp; +char *arg; +{ + struct action *new; + new = Action_new(); + new->next = *app; + *app = new; + new->type = type; + new->sp = sp; + if( type==SHIFT ){ + new->x.stp = (struct state *)arg; + }else{ + new->x.rp = (struct rule *)arg; + } +} +/********************** New code to implement the "acttab" module ***********/ +/* +** This module implements routines use to construct the yy_action[] table. +*/ + +/* +** The state of the yy_action table under construction is an instance of +** the following structure +*/ +typedef struct acttab acttab; +struct acttab { + int nAction; /* Number of used slots in aAction[] */ + int nActionAlloc; /* Slots allocated for aAction[] */ + struct { + int lookahead; /* Value of the lookahead token */ + int action; /* Action to take on the given lookahead */ + } *aAction, /* The yy_action[] table under construction */ + *aLookahead; /* A single new transaction set */ + int mnLookahead; /* Minimum aLookahead[].lookahead */ + int mnAction; /* Action associated with mnLookahead */ + int mxLookahead; /* Maximum aLookahead[].lookahead */ + int nLookahead; /* Used slots in aLookahead[] */ + int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ +}; + +/* Return the number of entries in the yy_action table */ +#define acttab_size(X) ((X)->nAction) + +/* The value for the N-th entry in yy_action */ +#define acttab_yyaction(X,N) ((X)->aAction[N].action) + +/* The value for the N-th entry in yy_lookahead */ +#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) + +/* Free all memory associated with the given acttab */ +void acttab_free(acttab *p){ + free( p->aAction ); + free( p->aLookahead ); + free( p ); +} + +/* Allocate a new acttab structure */ +acttab *acttab_alloc(void){ + acttab *p = calloc( 1, sizeof(*p) ); + if( p==0 ){ + fprintf(stderr,"Unable to allocate memory for a new acttab."); + exit(1); + } + memset(p, 0, sizeof(*p)); + return p; +} + +/* Add a new action to the current transaction set +*/ +void acttab_action(acttab *p, int lookahead, int action){ + if( p->nLookahead>=p->nLookaheadAlloc ){ + p->nLookaheadAlloc += 25; + p->aLookahead = realloc( p->aLookahead, + sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); + if( p->aLookahead==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + } + if( p->nLookahead==0 ){ + p->mxLookahead = lookahead; + p->mnLookahead = lookahead; + p->mnAction = action; + }else{ + if( p->mxLookaheadmxLookahead = lookahead; + if( p->mnLookahead>lookahead ){ + p->mnLookahead = lookahead; + p->mnAction = action; + } + } + p->aLookahead[p->nLookahead].lookahead = lookahead; + p->aLookahead[p->nLookahead].action = action; + p->nLookahead++; +} + +/* +** Add the transaction set built up with prior calls to acttab_action() +** into the current action table. Then reset the transaction set back +** to an empty set in preparation for a new round of acttab_action() calls. +** +** Return the offset into the action table of the new transaction. +*/ +int acttab_insert(acttab *p){ + int i, j, k, n; + assert( p->nLookahead>0 ); + + /* Make sure we have enough space to hold the expanded action table + ** in the worst case. The worst case occurs if the transaction set + ** must be appended to the current action table + */ + n = p->mxLookahead + 1; + if( p->nAction + n >= p->nActionAlloc ){ + int oldAlloc = p->nActionAlloc; + p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; + p->aAction = realloc( p->aAction, + sizeof(p->aAction[0])*p->nActionAlloc); + if( p->aAction==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=oldAlloc; inActionAlloc; i++){ + p->aAction[i].lookahead = -1; + p->aAction[i].action = -1; + } + } + + /* Scan the existing action table looking for an offset where we can + ** insert the current transaction set. Fall out of the loop when that + ** offset is found. In the worst case, we fall out of the loop when + ** i reaches p->nAction, which means we append the new transaction set. + ** + ** i is the index in p->aAction[] where p->mnLookahead is inserted. + */ + for(i=0; inAction+p->mnLookahead; i++){ + if( p->aAction[i].lookahead<0 ){ + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 ) break; + if( p->aAction[k].lookahead>=0 ) break; + } + if( jnLookahead ) continue; + for(j=0; jnAction; j++){ + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; + } + if( j==p->nAction ){ + break; /* Fits in empty slots */ + } + }else if( p->aAction[i].lookahead==p->mnLookahead ){ + if( p->aAction[i].action!=p->mnAction ) continue; + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 || k>=p->nAction ) break; + if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; + if( p->aLookahead[j].action!=p->aAction[k].action ) break; + } + if( jnLookahead ) continue; + n = 0; + for(j=0; jnAction; j++){ + if( p->aAction[j].lookahead<0 ) continue; + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; + } + if( n==p->nLookahead ){ + break; /* Same as a prior transaction set */ + } + } + } + /* Insert transaction set at index i. */ + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + p->aAction[k] = p->aLookahead[j]; + if( k>=p->nAction ) p->nAction = k+1; + } + p->nLookahead = 0; + + /* Return the offset that is added to the lookahead in order to get the + ** index into yy_action of the action */ + return i - p->mnLookahead; +} + +/********************** From the file "build.c" *****************************/ +/* +** Routines to construction the finite state machine for the LEMON +** parser generator. +*/ + +/* Find a precedence symbol of every rule in the grammar. +** +** Those rules which have a precedence symbol coded in the input +** grammar using the "[symbol]" construct will already have the +** rp->precsym field filled. Other rules take as their precedence +** symbol the first RHS symbol with a defined precedence. If there +** are not RHS symbols with a defined precedence, the precedence +** symbol field is left blank. +*/ +void FindRulePrecedences(xp) +struct lemon *xp; +{ + struct rule *rp; + for(rp=xp->rule; rp; rp=rp->next){ + if( rp->precsym==0 ){ + int i, j; + for(i=0; inrhs && rp->precsym==0; i++){ + struct symbol *sp = rp->rhs[i]; + if( sp->type==MULTITERMINAL ){ + for(j=0; jnsubsym; j++){ + if( sp->subsym[j]->prec>=0 ){ + rp->precsym = sp->subsym[j]; + break; + } + } + }else if( sp->prec>=0 ){ + rp->precsym = rp->rhs[i]; + } + } + } + } + return; +} + +/* Find all nonterminals which will generate the empty string. +** Then go back and compute the first sets of every nonterminal. +** The first set is the set of all terminal symbols which can begin +** a string generated by that nonterminal. +*/ +void FindFirstSets(lemp) +struct lemon *lemp; +{ + int i, j; + struct rule *rp; + int progress; + + for(i=0; insymbol; i++){ + lemp->symbols[i]->lambda = LEMON_FALSE; + } + for(i=lemp->nterminal; insymbol; i++){ + lemp->symbols[i]->firstset = SetNew(); + } + + /* First compute all lambdas */ + do{ + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->lhs->lambda ) continue; + for(i=0; inrhs; i++){ + struct symbol *sp = rp->rhs[i]; + if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break; + } + if( i==rp->nrhs ){ + rp->lhs->lambda = LEMON_TRUE; + progress = 1; + } + } + }while( progress ); + + /* Now compute all first sets */ + do{ + struct symbol *s1, *s2; + progress = 0; + for(rp=lemp->rule; rp; rp=rp->next){ + s1 = rp->lhs; + for(i=0; inrhs; i++){ + s2 = rp->rhs[i]; + if( s2->type==TERMINAL ){ + progress += SetAdd(s1->firstset,s2->index); + break; + }else if( s2->type==MULTITERMINAL ){ + for(j=0; jnsubsym; j++){ + progress += SetAdd(s1->firstset,s2->subsym[j]->index); + } + break; + }else if( s1==s2 ){ + if( s1->lambda==LEMON_FALSE ) break; + }else{ + progress += SetUnion(s1->firstset,s2->firstset); + if( s2->lambda==LEMON_FALSE ) break; + } + } + } + }while( progress ); + return; +} + +/* Compute all LR(0) states for the grammar. Links +** are added to between some states so that the LR(1) follow sets +** can be computed later. +*/ +PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */ +void FindStates(lemp) +struct lemon *lemp; +{ + struct symbol *sp; + struct rule *rp; + + Configlist_init(); + + /* Find the start symbol */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ){ + ErrorMsg(lemp->filename,0, +"The specified start symbol \"%s\" is not \ +in a nonterminal of the grammar. \"%s\" will be used as the start \ +symbol instead.",lemp->start,lemp->rule->lhs->name); + lemp->errorcnt++; + sp = lemp->rule->lhs; + } + }else{ + sp = lemp->rule->lhs; + } + + /* Make sure the start symbol doesn't occur on the right-hand side of + ** any rule. Report an error if it does. (YACC would generate a new + ** start symbol in this case.) */ + for(rp=lemp->rule; rp; rp=rp->next){ + int i; + for(i=0; inrhs; i++){ + if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ + ErrorMsg(lemp->filename,0, +"The start symbol \"%s\" occurs on the \ +right-hand side of a rule. This will result in a parser which \ +does not work properly.",sp->name); + lemp->errorcnt++; + } + } + } + + /* The basis configuration set for the first state + ** is all rules which have the start symbol as their + ** left-hand side */ + for(rp=sp->rule; rp; rp=rp->nextlhs){ + struct config *newcfp; + rp->lhsStart = 1; + newcfp = Configlist_addbasis(rp,0); + SetAdd(newcfp->fws,0); + } + + /* Compute the first state. All other states will be + ** computed automatically during the computation of the first one. + ** The returned pointer to the first state is not used. */ + (void)getstate(lemp); + return; +} + +/* Return a pointer to a state which is described by the configuration +** list which has been built from calls to Configlist_add. +*/ +PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */ +PRIVATE struct state *getstate(lemp) +struct lemon *lemp; +{ + struct config *cfp, *bp; + struct state *stp; + + /* Extract the sorted basis of the new state. The basis was constructed + ** by prior calls to "Configlist_addbasis()". */ + Configlist_sortbasis(); + bp = Configlist_basis(); + + /* Get a state with the same basis */ + stp = State_find(bp); + if( stp ){ + /* A state with the same basis already exists! Copy all the follow-set + ** propagation links from the state under construction into the + ** preexisting state, then return a pointer to the preexisting state */ + struct config *x, *y; + for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ + Plink_copy(&y->bplp,x->bplp); + Plink_delete(x->fplp); + x->fplp = x->bplp = 0; + } + cfp = Configlist_return(); + Configlist_eat(cfp); + }else{ + /* This really is a new state. Construct all the details */ + Configlist_closure(lemp); /* Compute the configuration closure */ + Configlist_sort(); /* Sort the configuration closure */ + cfp = Configlist_return(); /* Get a pointer to the config list */ + stp = State_new(); /* A new state structure */ + MemoryCheck(stp); + stp->bp = bp; /* Remember the configuration basis */ + stp->cfp = cfp; /* Remember the configuration closure */ + stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ + stp->ap = 0; /* No actions, yet. */ + State_insert(stp,stp->bp); /* Add to the state table */ + buildshifts(lemp,stp); /* Recursively compute successor states */ + } + return stp; +} + +/* +** Return true if two symbols are the same. +*/ +int same_symbol(a,b) +struct symbol *a; +struct symbol *b; +{ + int i; + if( a==b ) return 1; + if( a->type!=MULTITERMINAL ) return 0; + if( b->type!=MULTITERMINAL ) return 0; + if( a->nsubsym!=b->nsubsym ) return 0; + for(i=0; insubsym; i++){ + if( a->subsym[i]!=b->subsym[i] ) return 0; + } + return 1; +} + +/* Construct all successor states to the given state. A "successor" +** state is any state which can be reached by a shift action. +*/ +PRIVATE void buildshifts(lemp,stp) +struct lemon *lemp; +struct state *stp; /* The state from which successors are computed */ +{ + struct config *cfp; /* For looping thru the config closure of "stp" */ + struct config *bcfp; /* For the inner loop on config closure of "stp" */ + struct config *new; /* */ + struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ + struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ + struct state *newstp; /* A pointer to a successor state */ + + /* Each configuration becomes complete after it contibutes to a successor + ** state. Initially, all configurations are incomplete */ + for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; + + /* Loop through all configurations of the state "stp" */ + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ + if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ + Configlist_reset(); /* Reset the new config set */ + sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ + + /* For every configuration in the state "stp" which has the symbol "sp" + ** following its dot, add the same configuration to the basis set under + ** construction but with the dot shifted one symbol to the right. */ + for(bcfp=cfp; bcfp; bcfp=bcfp->next){ + if( bcfp->status==COMPLETE ) continue; /* Already used */ + if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ + bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ + if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ + bcfp->status = COMPLETE; /* Mark this config as used */ + new = Configlist_addbasis(bcfp->rp,bcfp->dot+1); + Plink_add(&new->bplp,bcfp); + } + + /* Get a pointer to the state described by the basis configuration set + ** constructed in the preceding loop */ + newstp = getstate(lemp); + + /* The state "newstp" is reached from the state "stp" by a shift action + ** on the symbol "sp" */ + if( sp->type==MULTITERMINAL ){ + int i; + for(i=0; insubsym; i++){ + Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); + } + }else{ + Action_add(&stp->ap,SHIFT,sp,(char *)newstp); + } + } +} + +/* +** Construct the propagation links +*/ +void FindLinks(lemp) +struct lemon *lemp; +{ + int i; + struct config *cfp, *other; + struct state *stp; + struct plink *plp; + + /* Housekeeping detail: + ** Add to every propagate link a pointer back to the state to + ** which the link is attached. */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + cfp->stp = stp; + } + } + + /* Convert all backlinks into forward links. Only the forward + ** links are used in the follow-set computation. */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ + for(plp=cfp->bplp; plp; plp=plp->next){ + other = plp->cfp; + Plink_add(&other->fplp,cfp); + } + } + } +} + +/* Compute all followsets. +** +** A followset is the set of all symbols which can come immediately +** after a configuration. +*/ +void FindFollowSets(lemp) +struct lemon *lemp; +{ + int i; + struct config *cfp; + struct plink *plp; + int progress; + int change; + + for(i=0; instate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + cfp->status = INCOMPLETE; + } + } + + do{ + progress = 0; + for(i=0; instate; i++){ + for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ + if( cfp->status==COMPLETE ) continue; + for(plp=cfp->fplp; plp; plp=plp->next){ + change = SetUnion(plp->cfp->fws,cfp->fws); + if( change ){ + plp->cfp->status = INCOMPLETE; + progress = 1; + } + } + cfp->status = COMPLETE; + } + } + }while( progress ); +} + +static int resolve_conflict(); + +/* Compute the reduce actions, and resolve conflicts. +*/ +void FindActions(lemp) +struct lemon *lemp; +{ + int i,j; + struct config *cfp; + struct state *stp; + struct symbol *sp; + struct rule *rp; + + /* Add all of the reduce actions + ** A reduce action is added for each element of the followset of + ** a configuration which has its dot at the extreme right. + */ + for(i=0; instate; i++){ /* Loop over all states */ + stp = lemp->sorted[i]; + for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ + if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ + for(j=0; jnterminal; j++){ + if( SetFind(cfp->fws,j) ){ + /* Add a reduce action to the state "stp" which will reduce by the + ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ + Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); + } + } + } + } + } + + /* Add the accepting token */ + if( lemp->start ){ + sp = Symbol_find(lemp->start); + if( sp==0 ) sp = lemp->rule->lhs; + }else{ + sp = lemp->rule->lhs; + } + /* Add to the first state (which is always the starting state of the + ** finite state machine) an action to ACCEPT if the lookahead is the + ** start nonterminal. */ + Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); + + /* Resolve conflicts */ + for(i=0; instate; i++){ + struct action *ap, *nap; + struct state *stp; + stp = lemp->sorted[i]; + /* assert( stp->ap ); */ + stp->ap = Action_sort(stp->ap); + for(ap=stp->ap; ap && ap->next; ap=ap->next){ + for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ + /* The two actions "ap" and "nap" have the same lookahead. + ** Figure out which one should be used */ + lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym); + } + } + } + + /* Report an error for each rule that can never be reduced. */ + for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; + for(i=0; instate; i++){ + struct action *ap; + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ + if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE; + } + } + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->canReduce ) continue; + ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); + lemp->errorcnt++; + } +} + +/* Resolve a conflict between the two given actions. If the +** conflict can't be resolved, return non-zero. +** +** NO LONGER TRUE: +** To resolve a conflict, first look to see if either action +** is on an error rule. In that case, take the action which +** is not associated with the error rule. If neither or both +** actions are associated with an error rule, then try to +** use precedence to resolve the conflict. +** +** If either action is a SHIFT, then it must be apx. This +** function won't work if apx->type==REDUCE and apy->type==SHIFT. +*/ +static int resolve_conflict(apx,apy,errsym) +struct action *apx; +struct action *apy; +struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ +{ + struct symbol *spx, *spy; + int errcnt = 0; + assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ + if( apx->type==SHIFT && apy->type==SHIFT ){ + apy->type = SSCONFLICT; + errcnt++; + } + if( apx->type==SHIFT && apy->type==REDUCE ){ + spx = apx->sp; + spy = apy->x.rp->precsym; + if( spy==0 || spx->prec<0 || spy->prec<0 ){ + /* Not enough precedence information. */ + apy->type = SRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ /* Lower precedence wins */ + apy->type = RD_RESOLVED; + }else if( spx->precprec ){ + apx->type = SH_RESOLVED; + }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ + apy->type = RD_RESOLVED; /* associativity */ + }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ + apx->type = SH_RESOLVED; + }else{ + assert( spx->prec==spy->prec && spx->assoc==NONE ); + apy->type = SRCONFLICT; + errcnt++; + } + }else if( apx->type==REDUCE && apy->type==REDUCE ){ + spx = apx->x.rp->precsym; + spy = apy->x.rp->precsym; + if( spx==0 || spy==0 || spx->prec<0 || + spy->prec<0 || spx->prec==spy->prec ){ + apy->type = RRCONFLICT; + errcnt++; + }else if( spx->prec>spy->prec ){ + apy->type = RD_RESOLVED; + }else if( spx->precprec ){ + apx->type = RD_RESOLVED; + } + }else{ + assert( + apx->type==SH_RESOLVED || + apx->type==RD_RESOLVED || + apx->type==SSCONFLICT || + apx->type==SRCONFLICT || + apx->type==RRCONFLICT || + apy->type==SH_RESOLVED || + apy->type==RD_RESOLVED || + apy->type==SSCONFLICT || + apy->type==SRCONFLICT || + apy->type==RRCONFLICT + ); + /* The REDUCE/SHIFT case cannot happen because SHIFTs come before + ** REDUCEs on the list. If we reach this point it must be because + ** the parser conflict had already been resolved. */ + } + return errcnt; +} +/********************* From the file "configlist.c" *************************/ +/* +** Routines to processing a configuration list and building a state +** in the LEMON parser generator. +*/ + +static struct config *freelist = 0; /* List of free configurations */ +static struct config *current = 0; /* Top of list of configurations */ +static struct config **currentend = 0; /* Last on list of configs */ +static struct config *basis = 0; /* Top of list of basis configs */ +static struct config **basisend = 0; /* End of list of basis configs */ + +/* Return a pointer to a new configuration */ +PRIVATE struct config *newconfig(){ + struct config *new; + if( freelist==0 ){ + int i; + int amt = 3; + freelist = (struct config *)calloc( amt, sizeof(struct config) ); + if( freelist==0 ){ + fprintf(stderr,"Unable to allocate memory for a new configuration."); + exit(1); + } + for(i=0; inext; + return new; +} + +/* The configuration "old" is no longer used */ +PRIVATE void deleteconfig(old) +struct config *old; +{ + old->next = freelist; + freelist = old; +} + +/* Initialized the configuration list builder */ +void Configlist_init(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_init(); + return; +} + +/* Initialized the configuration list builder */ +void Configlist_reset(){ + current = 0; + currentend = ¤t; + basis = 0; + basisend = &basis; + Configtable_clear(0); + return; +} + +/* Add another configuration to the configuration list */ +struct config *Configlist_add(rp,dot) +struct rule *rp; /* The rule */ +int dot; /* Index into the RHS of the rule where the dot goes */ +{ + struct config *cfp, model; + + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + Configtable_insert(cfp); + } + return cfp; +} + +/* Add a basis configuration to the configuration list */ +struct config *Configlist_addbasis(rp,dot) +struct rule *rp; +int dot; +{ + struct config *cfp, model; + + assert( basisend!=0 ); + assert( currentend!=0 ); + model.rp = rp; + model.dot = dot; + cfp = Configtable_find(&model); + if( cfp==0 ){ + cfp = newconfig(); + cfp->rp = rp; + cfp->dot = dot; + cfp->fws = SetNew(); + cfp->stp = 0; + cfp->fplp = cfp->bplp = 0; + cfp->next = 0; + cfp->bp = 0; + *currentend = cfp; + currentend = &cfp->next; + *basisend = cfp; + basisend = &cfp->bp; + Configtable_insert(cfp); + } + return cfp; +} + +/* Compute the closure of the configuration list */ +void Configlist_closure(lemp) +struct lemon *lemp; +{ + struct config *cfp, *newcfp; + struct rule *rp, *newrp; + struct symbol *sp, *xsp; + int i, dot; + + assert( currentend!=0 ); + for(cfp=current; cfp; cfp=cfp->next){ + rp = cfp->rp; + dot = cfp->dot; + if( dot>=rp->nrhs ) continue; + sp = rp->rhs[dot]; + if( sp->type==NONTERMINAL ){ + if( sp->rule==0 && sp!=lemp->errsym ){ + ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", + sp->name); + lemp->errorcnt++; + } + for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ + newcfp = Configlist_add(newrp,0); + for(i=dot+1; inrhs; i++){ + xsp = rp->rhs[i]; + if( xsp->type==TERMINAL ){ + SetAdd(newcfp->fws,xsp->index); + break; + }else if( xsp->type==MULTITERMINAL ){ + int k; + for(k=0; knsubsym; k++){ + SetAdd(newcfp->fws, xsp->subsym[k]->index); + } + break; + }else{ + SetUnion(newcfp->fws,xsp->firstset); + if( xsp->lambda==LEMON_FALSE ) break; + } + } + if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); + } + } + } + return; +} + +/* Sort the configuration list */ +void Configlist_sort(){ + current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); + currentend = 0; + return; +} + +/* Sort the basis configuration list */ +void Configlist_sortbasis(){ + basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); + basisend = 0; + return; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_return(){ + struct config *old; + old = current; + current = 0; + currentend = 0; + return old; +} + +/* Return a pointer to the head of the configuration list and +** reset the list */ +struct config *Configlist_basis(){ + struct config *old; + old = basis; + basis = 0; + basisend = 0; + return old; +} + +/* Free all elements of the given configuration list */ +void Configlist_eat(cfp) +struct config *cfp; +{ + struct config *nextcfp; + for(; cfp; cfp=nextcfp){ + nextcfp = cfp->next; + assert( cfp->fplp==0 ); + assert( cfp->bplp==0 ); + if( cfp->fws ) SetFree(cfp->fws); + deleteconfig(cfp); + } + return; +} +/***************** From the file "error.c" *********************************/ +/* +** Code for printing error message. +*/ + +/* Find a good place to break "msg" so that its length is at least "min" +** but no more than "max". Make the point as close to max as possible. +*/ +static int findbreak(msg,min,max) +char *msg; +int min; +int max; +{ + int i,spot; + char c; + for(i=spot=min; i<=max; i++){ + c = msg[i]; + if( c=='\t' ) msg[i] = ' '; + if( c=='\n' ){ msg[i] = ' '; spot = i; break; } + if( c==0 ){ spot = i; break; } + if( c=='-' && i0 ){ + sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno); + }else{ + sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); + } + prefixsize = lemonStrlen(prefix); + availablewidth = LINEWIDTH - prefixsize; + + /* Generate the error message */ + vsprintf(errmsg,format,ap); + va_end(ap); + errmsgsize = lemonStrlen(errmsg); + /* Remove trailing '\n's from the error message. */ + while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){ + errmsg[--errmsgsize] = 0; + } + + /* Print the error message */ + base = 0; + while( errmsg[base]!=0 ){ + end = restart = findbreak(&errmsg[base],0,availablewidth); + restart += base; + while( errmsg[restart]==' ' ) restart++; + fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]); + base = restart; + } +} +/**************** From the file "main.c" ************************************/ +/* +** Main program file for the LEMON parser generator. +*/ + +/* Report an out-of-memory condition and abort. This function +** is used mostly by the "MemoryCheck" macro in struct.h +*/ +void memory_error(){ + fprintf(stderr,"Out of memory. Aborting...\n"); + exit(1); +} + +static int nDefine = 0; /* Number of -D options on the command line */ +static char **azDefine = 0; /* Name of the -D macros */ + +/* This routine is called with the argument to each -D command-line option. +** Add the macro defined to the azDefine array. +*/ +static void handle_D_option(char *z){ + char **paz; + nDefine++; + azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine); + if( azDefine==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + paz = &azDefine[nDefine-1]; + *paz = malloc( lemonStrlen(z)+1 ); + if( *paz==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + strcpy(*paz, z); + for(z=*paz; *z && *z!='='; z++){} + *z = 0; +} + + +/* The main program. Parse the command line and do it... */ +int main(argc,argv) +int argc; +char **argv; +{ + static int version = 0; + static int rpflag = 0; + static int basisflag = 0; + static int compress = 0; + static int quiet = 0; + static int statistics = 0; + static int mhflag = 0; + static int nolinenosflag = 0; + static struct s_options options[] = { + {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, + {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, + {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, + {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, + {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, + {OPT_FLAG, "s", (char*)&statistics, + "Print parser stats to standard output."}, + {OPT_FLAG, "x", (char*)&version, "Print the version number."}, + {OPT_FLAG,0,0,0} + }; + int i; + struct lemon lem; + + OptInit(argv,options,stderr); + if( version ){ + printf("Lemon version 1.0\n"); + exit(0); + } + if( OptNArgs()!=1 ){ + fprintf(stderr,"Exactly one filename argument is required.\n"); + exit(1); + } + memset(&lem, 0, sizeof(lem)); + lem.errorcnt = 0; + + /* Initialize the machine */ + Strsafe_init(); + Symbol_init(); + State_init(); + lem.argv0 = argv[0]; + lem.filename = OptArg(0); + lem.basisflag = basisflag; + lem.nolinenosflag = nolinenosflag; + Symbol_new("$"); + lem.errsym = Symbol_new("error"); + lem.errsym->useCnt = 0; + + /* Parse the input file */ + Parse(&lem); + if( lem.errorcnt ) exit(lem.errorcnt); + if( lem.nrule==0 ){ + fprintf(stderr,"Empty grammar.\n"); + exit(1); + } + + /* Count and index the symbols of the grammar */ + lem.nsymbol = Symbol_count(); + Symbol_new("{default}"); + lem.symbols = Symbol_arrayof(); + for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; + qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), + (int(*)())Symbolcmpp); + for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; + for(i=1; isupper(lem.symbols[i]->name[0]); i++); + lem.nterminal = i; + + /* Generate a reprint of the grammar, if requested on the command line */ + if( rpflag ){ + Reprint(&lem); + }else{ + /* Initialize the size for all follow and first sets */ + SetSize(lem.nterminal+1); + + /* Find the precedence for every production rule (that has one) */ + FindRulePrecedences(&lem); + + /* Compute the lambda-nonterminals and the first-sets for every + ** nonterminal */ + FindFirstSets(&lem); + + /* Compute all LR(0) states. Also record follow-set propagation + ** links so that the follow-set can be computed later */ + lem.nstate = 0; + FindStates(&lem); + lem.sorted = State_arrayof(); + + /* Tie up loose ends on the propagation links */ + FindLinks(&lem); + + /* Compute the follow set of every reducible configuration */ + FindFollowSets(&lem); + + /* Compute the action tables */ + FindActions(&lem); + + /* Compress the action tables */ + if( compress==0 ) CompressTables(&lem); + + /* Reorder and renumber the states so that states with fewer choices + ** occur at the end. */ + ResortStates(&lem); + + /* Generate a report of the parser generated. (the "y.output" file) */ + if( !quiet ) ReportOutput(&lem); + + /* Generate the source code for the parser */ + ReportTable(&lem, mhflag); + + /* Produce a header file for use by the scanner. (This step is + ** omitted if the "-m" option is used because makeheaders will + ** generate the file for us.) */ + if( !mhflag ) ReportHeader(&lem); + } + if( statistics ){ + printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", + lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); + printf(" %d states, %d parser table entries, %d conflicts\n", + lem.nstate, lem.tablesize, lem.nconflict); + } + if( lem.nconflict ){ + fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); + } + exit(lem.errorcnt + lem.nconflict); + return (lem.errorcnt + lem.nconflict); +} +/******************** From the file "msort.c" *******************************/ +/* +** A generic merge-sort program. +** +** USAGE: +** Let "ptr" be a pointer to some structure which is at the head of +** a null-terminated list. Then to sort the list call: +** +** ptr = msort(ptr,&(ptr->next),cmpfnc); +** +** In the above, "cmpfnc" is a pointer to a function which compares +** two instances of the structure and returns an integer, as in +** strcmp. The second argument is a pointer to the pointer to the +** second element of the linked list. This address is used to compute +** the offset to the "next" field within the structure. The offset to +** the "next" field must be constant for all structures in the list. +** +** The function returns a new pointer which is the head of the list +** after sorting. +** +** ALGORITHM: +** Merge-sort. +*/ + +/* +** Return a pointer to the next structure in the linked list. +*/ +#define NEXT(A) (*(char**)(((unsigned long)A)+offset)) + +/* +** Inputs: +** a: A sorted, null-terminated linked list. (May be null). +** b: A sorted, null-terminated linked list. (May be null). +** cmp: A pointer to the comparison function. +** offset: Offset in the structure to the "next" field. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** of both a and b. +** +** Side effects: +** The "next" pointers for elements in the lists a and b are +** changed. +*/ +static char *merge( + char *a, + char *b, + int (*cmp)(const char*,const char*), + int offset +){ + char *ptr, *head; + + if( a==0 ){ + head = b; + }else if( b==0 ){ + head = a; + }else{ + if( (*cmp)(a,b)<0 ){ + ptr = a; + a = NEXT(a); + }else{ + ptr = b; + b = NEXT(b); + } + head = ptr; + while( a && b ){ + if( (*cmp)(a,b)<0 ){ + NEXT(ptr) = a; + ptr = a; + a = NEXT(a); + }else{ + NEXT(ptr) = b; + ptr = b; + b = NEXT(b); + } + } + if( a ) NEXT(ptr) = a; + else NEXT(ptr) = b; + } + return head; +} + +/* +** Inputs: +** list: Pointer to a singly-linked list of structures. +** next: Pointer to pointer to the second element of the list. +** cmp: A comparison function. +** +** Return Value: +** A pointer to the head of a sorted list containing the elements +** orginally in list. +** +** Side effects: +** The "next" pointers for elements in list are changed. +*/ +#define LISTSIZE 30 +static char *msort( + char *list, + char **next, + int (*cmp)(const char*,const char*) +){ + unsigned long offset; + char *ep; + char *set[LISTSIZE]; + int i; + offset = (unsigned long)next - (unsigned long)list; + for(i=0; istate = WAITING_FOR_DECL_KEYWORD; + }else if( islower(x[0]) ){ + psp->lhs = Symbol_new(x); + psp->nrhs = 0; + psp->lhsalias = 0; + psp->state = WAITING_FOR_ARROW; + }else if( x[0]=='{' ){ + if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"There is no prior rule opon which to attach the code \ +fragment which begins on this line."); + psp->errorcnt++; + }else if( psp->prevrule->code!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Code fragment beginning on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->line = psp->tokenlineno; + psp->prevrule->code = &x[1]; + } + }else if( x[0]=='[' ){ + psp->state = PRECEDENCE_MARK_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Token \"%s\" should be either \"%%\" or a nonterminal name.", + x); + psp->errorcnt++; + } + break; + case PRECEDENCE_MARK_1: + if( !isupper(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "The precedence symbol must be a terminal."); + psp->errorcnt++; + }else if( psp->prevrule==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "There is no prior rule to assign precedence \"[%s]\".",x); + psp->errorcnt++; + }else if( psp->prevrule->precsym!=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, +"Precedence mark on this line is not the first \ +to follow the previous rule."); + psp->errorcnt++; + }else{ + psp->prevrule->precsym = Symbol_new(x); + } + psp->state = PRECEDENCE_MARK_2; + break; + case PRECEDENCE_MARK_2: + if( x[0]!=']' ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"]\" on precedence mark."); + psp->errorcnt++; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + break; + case WAITING_FOR_ARROW: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else if( x[0]=='(' ){ + psp->state = LHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Expected to see a \":\" following the LHS symbol \"%s\".", + psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->lhsalias = x; + psp->state = LHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the LHS \"%s\"\n", + x,psp->lhs->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = LHS_ALIAS_3; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case LHS_ALIAS_3: + if( x[0]==':' && x[1]==':' && x[2]=='=' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \"->\" following: \"%s(%s)\".", + psp->lhs->name,psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case IN_RHS: + if( x[0]=='.' ){ + struct rule *rp; + rp = (struct rule *)calloc( sizeof(struct rule) + + sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); + if( rp==0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't allocate enough memory for this rule."); + psp->errorcnt++; + psp->prevrule = 0; + }else{ + int i; + rp->ruleline = psp->tokenlineno; + rp->rhs = (struct symbol**)&rp[1]; + rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]); + for(i=0; inrhs; i++){ + rp->rhs[i] = psp->rhs[i]; + rp->rhsalias[i] = psp->alias[i]; + } + rp->lhs = psp->lhs; + rp->lhsalias = psp->lhsalias; + rp->nrhs = psp->nrhs; + rp->code = 0; + rp->precsym = 0; + rp->index = psp->gp->nrule++; + rp->nextlhs = rp->lhs->rule; + rp->lhs->rule = rp; + rp->next = 0; + if( psp->firstrule==0 ){ + psp->firstrule = psp->lastrule = rp; + }else{ + psp->lastrule->next = rp; + psp->lastrule = rp; + } + psp->prevrule = rp; + } + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isalpha(x[0]) ){ + if( psp->nrhs>=MAXRHS ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Too many symbols on RHS of rule beginning at \"%s\".", + x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + }else{ + psp->rhs[psp->nrhs] = Symbol_new(x); + psp->alias[psp->nrhs] = 0; + psp->nrhs++; + } + }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ + struct symbol *msp = psp->rhs[psp->nrhs-1]; + if( msp->type!=MULTITERMINAL ){ + struct symbol *origsp = msp; + msp = calloc(1,sizeof(*msp)); + memset(msp, 0, sizeof(*msp)); + msp->type = MULTITERMINAL; + msp->nsubsym = 1; + msp->subsym = calloc(1,sizeof(struct symbol*)); + msp->subsym[0] = origsp; + msp->name = origsp->name; + psp->rhs[psp->nrhs-1] = msp; + } + msp->nsubsym++; + msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym); + msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); + if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Cannot form a compound containing a non-terminal"); + psp->errorcnt++; + } + }else if( x[0]=='(' && psp->nrhs>0 ){ + psp->state = RHS_ALIAS_1; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal character on RHS of rule: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_1: + if( isalpha(x[0]) ){ + psp->alias[psp->nrhs-1] = x; + psp->state = RHS_ALIAS_2; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", + x,psp->rhs[psp->nrhs-1]->name); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case RHS_ALIAS_2: + if( x[0]==')' ){ + psp->state = IN_RHS; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); + psp->errorcnt++; + psp->state = RESYNC_AFTER_RULE_ERROR; + } + break; + case WAITING_FOR_DECL_KEYWORD: + if( isalpha(x[0]) ){ + psp->declkeyword = x; + psp->declargslot = 0; + psp->decllinenoslot = 0; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + if( strcmp(x,"name")==0 ){ + psp->declargslot = &(psp->gp->name); + psp->insertLineMacro = 0; + }else if( strcmp(x,"include")==0 ){ + psp->declargslot = &(psp->gp->include); + }else if( strcmp(x,"code")==0 ){ + psp->declargslot = &(psp->gp->extracode); + }else if( strcmp(x,"token_destructor")==0 ){ + psp->declargslot = &psp->gp->tokendest; + }else if( strcmp(x,"default_destructor")==0 ){ + psp->declargslot = &psp->gp->vardest; + }else if( strcmp(x,"token_prefix")==0 ){ + psp->declargslot = &psp->gp->tokenprefix; + psp->insertLineMacro = 0; + }else if( strcmp(x,"syntax_error")==0 ){ + psp->declargslot = &(psp->gp->error); + }else if( strcmp(x,"parse_accept")==0 ){ + psp->declargslot = &(psp->gp->accept); + }else if( strcmp(x,"parse_failure")==0 ){ + psp->declargslot = &(psp->gp->failure); + }else if( strcmp(x,"stack_overflow")==0 ){ + psp->declargslot = &(psp->gp->overflow); + }else if( strcmp(x,"extra_argument")==0 ){ + psp->declargslot = &(psp->gp->arg); + psp->insertLineMacro = 0; + }else if( strcmp(x,"token_type")==0 ){ + psp->declargslot = &(psp->gp->tokentype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"default_type")==0 ){ + psp->declargslot = &(psp->gp->vartype); + psp->insertLineMacro = 0; + }else if( strcmp(x,"stack_size")==0 ){ + psp->declargslot = &(psp->gp->stacksize); + psp->insertLineMacro = 0; + }else if( strcmp(x,"start_symbol")==0 ){ + psp->declargslot = &(psp->gp->start); + psp->insertLineMacro = 0; + }else if( strcmp(x,"left")==0 ){ + psp->preccounter++; + psp->declassoc = LEFT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"right")==0 ){ + psp->preccounter++; + psp->declassoc = RIGHT; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"nonassoc")==0 ){ + psp->preccounter++; + psp->declassoc = NONE; + psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; + }else if( strcmp(x,"destructor")==0 ){ + psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; + }else if( strcmp(x,"type")==0 ){ + psp->state = WAITING_FOR_DATATYPE_SYMBOL; + }else if( strcmp(x,"fallback")==0 ){ + psp->fallback = 0; + psp->state = WAITING_FOR_FALLBACK_ID; + }else if( strcmp(x,"wildcard")==0 ){ + psp->state = WAITING_FOR_WILDCARD_ID; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Unknown declaration keyword: \"%%%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal declaration keyword: \"%s\".",x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_DESTRUCTOR_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %destructor keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_new(x); + psp->declargslot = &sp->destructor; + psp->decllinenoslot = &sp->destLineno; + psp->insertLineMacro = 1; + psp->state = WAITING_FOR_DECL_ARG; + } + break; + case WAITING_FOR_DATATYPE_SYMBOL: + if( !isalpha(x[0]) ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol name missing after %destructor keyword"); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + }else{ + struct symbol *sp = Symbol_new(x); + psp->declargslot = &sp->datatype; + psp->insertLineMacro = 0; + psp->state = WAITING_FOR_DECL_ARG; + } + break; + case WAITING_FOR_PRECEDENCE_SYMBOL: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( isupper(x[0]) ){ + struct symbol *sp; + sp = Symbol_new(x); + if( sp->prec>=0 ){ + ErrorMsg(psp->filename,psp->tokenlineno, + "Symbol \"%s\" has already be given a precedence.",x); + psp->errorcnt++; + }else{ + sp->prec = psp->preccounter; + sp->assoc = psp->declassoc; + } + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Can't assign a precedence to \"%s\".",x); + psp->errorcnt++; + } + break; + case WAITING_FOR_DECL_ARG: + if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ + char *zOld, *zNew, *zBuf, *z; + int nOld, n, nLine, nNew, nBack; + int addLineMacro; + char zLine[50]; + zNew = x; + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; + nNew = lemonStrlen(zNew); + if( *psp->declargslot ){ + zOld = *psp->declargslot; + }else{ + zOld = ""; + } + nOld = lemonStrlen(zOld); + n = nOld + nNew + 20; + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); + if( addLineMacro ){ + for(z=psp->filename, nBack=0; *z; z++){ + if( *z=='\\' ) nBack++; + } + sprintf(zLine, "#line %d ", psp->tokenlineno); + nLine = lemonStrlen(zLine); + n += nLine + lemonStrlen(psp->filename) + nBack; + } + *psp->declargslot = zBuf = realloc(*psp->declargslot, n); + zBuf += nOld; + if( addLineMacro ){ + if( nOld && zBuf[-1]!='\n' ){ + *(zBuf++) = '\n'; + } + memcpy(zBuf, zLine, nLine); + zBuf += nLine; + *(zBuf++) = '"'; + for(z=psp->filename; *z; z++){ + if( *z=='\\' ){ + *(zBuf++) = '\\'; + } + *(zBuf++) = *z; + } + *(zBuf++) = '"'; + *(zBuf++) = '\n'; + } + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ + psp->decllinenoslot[0] = psp->tokenlineno; + } + memcpy(zBuf, zNew, nNew); + zBuf += nNew; + *zBuf = 0; + psp->state = WAITING_FOR_DECL_OR_RULE; + }else{ + ErrorMsg(psp->filename,psp->tokenlineno, + "Illegal argument to %%%s: %s",psp->declkeyword,x); + psp->errorcnt++; + psp->state = RESYNC_AFTER_DECL_ERROR; + } + break; + case WAITING_FOR_FALLBACK_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%fallback argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->fallback==0 ){ + psp->fallback = sp; + }else if( sp->fallback ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "More than one fallback assigned to token %s", x); + psp->errorcnt++; + }else{ + sp->fallback = psp->fallback; + psp->gp->has_fallback = 1; + } + } + break; + case WAITING_FOR_WILDCARD_ID: + if( x[0]=='.' ){ + psp->state = WAITING_FOR_DECL_OR_RULE; + }else if( !isupper(x[0]) ){ + ErrorMsg(psp->filename, psp->tokenlineno, + "%%wildcard argument \"%s\" should be a token", x); + psp->errorcnt++; + }else{ + struct symbol *sp = Symbol_new(x); + if( psp->gp->wildcard==0 ){ + psp->gp->wildcard = sp; + }else{ + ErrorMsg(psp->filename, psp->tokenlineno, + "Extra wildcard to token: %s", x); + psp->errorcnt++; + } + } + break; + case RESYNC_AFTER_RULE_ERROR: +/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; +** break; */ + case RESYNC_AFTER_DECL_ERROR: + if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; + if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; + break; + } +} + +/* Run the preprocessor over the input file text. The global variables +** azDefine[0] through azDefine[nDefine-1] contains the names of all defined +** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and +** comments them out. Text in between is also commented out as appropriate. +*/ +static void preprocess_input(char *z){ + int i, j, k, n; + int exclude = 0; + int start = 0; + int lineno = 1; + int start_lineno = 1; + for(i=0; z[i]; i++){ + if( z[i]=='\n' ) lineno++; + if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; + if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ + if( exclude ){ + exclude--; + if( exclude==0 ){ + for(j=start; jfilename; + ps.errorcnt = 0; + ps.state = INITIALIZE; + + /* Begin by reading the input file */ + fp = fopen(ps.filename,"rb"); + if( fp==0 ){ + ErrorMsg(ps.filename,0,"Can't open this file for reading."); + gp->errorcnt++; + return; + } + fseek(fp,0,2); + filesize = ftell(fp); + rewind(fp); + filebuf = (char *)malloc( filesize+1 ); + if( filebuf==0 ){ + ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.", + filesize+1); + gp->errorcnt++; + return; + } + if( fread(filebuf,1,filesize,fp)!=filesize ){ + ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", + filesize); + free(filebuf); + gp->errorcnt++; + return; + } + fclose(fp); + filebuf[filesize] = 0; + + /* Make an initial pass through the file to handle %ifdef and %ifndef */ + preprocess_input(filebuf); + + /* Now scan the text of the input file */ + lineno = 1; + for(cp=filebuf; (c= *cp)!=0; ){ + if( c=='\n' ) lineno++; /* Keep track of the line number */ + if( isspace(c) ){ cp++; continue; } /* Skip all white space */ + if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ + cp+=2; + while( (c= *cp)!=0 && c!='\n' ) cp++; + continue; + } + if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ + cp+=2; + while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c ) cp++; + continue; + } + ps.tokenstart = cp; /* Mark the beginning of the token */ + ps.tokenlineno = lineno; /* Linenumber on which token begins */ + if( c=='\"' ){ /* String literals */ + cp++; + while( (c= *cp)!=0 && c!='\"' ){ + if( c=='\n' ) lineno++; + cp++; + } + if( c==0 ){ + ErrorMsg(ps.filename,startline, +"String starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( c=='{' ){ /* A block of C code */ + int level; + cp++; + for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ + if( c=='\n' ) lineno++; + else if( c=='{' ) level++; + else if( c=='}' ) level--; + else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ + int prevc; + cp = &cp[2]; + prevc = 0; + while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ + if( c=='\n' ) lineno++; + prevc = c; + cp++; + } + }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ + cp = &cp[2]; + while( (c= *cp)!=0 && c!='\n' ) cp++; + if( c ) lineno++; + }else if( c=='\'' || c=='\"' ){ /* String a character literals */ + int startchar, prevc; + startchar = c; + prevc = 0; + for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ + if( c=='\n' ) lineno++; + if( prevc=='\\' ) prevc = 0; + else prevc = c; + } + } + } + if( c==0 ){ + ErrorMsg(ps.filename,ps.tokenlineno, +"C code starting on this line is not terminated before the end of the file."); + ps.errorcnt++; + nextcp = cp; + }else{ + nextcp = cp+1; + } + }else if( isalnum(c) ){ /* Identifiers */ + while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ + cp += 3; + nextcp = cp; + }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ + cp += 2; + while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; + nextcp = cp; + }else{ /* All other (one character) operators */ + cp++; + nextcp = cp; + } + c = *cp; + *cp = 0; /* Null terminate the token */ + parseonetoken(&ps); /* Parse the token */ + *cp = c; /* Restore the buffer */ + cp = nextcp; + } + free(filebuf); /* Release the buffer after parsing */ + gp->rule = ps.firstrule; + gp->errorcnt = ps.errorcnt; +} +/*************************** From the file "plink.c" *********************/ +/* +** Routines processing configuration follow-set propagation links +** in the LEMON parser generator. +*/ +static struct plink *plink_freelist = 0; + +/* Allocate a new plink */ +struct plink *Plink_new(){ + struct plink *new; + + if( plink_freelist==0 ){ + int i; + int amt = 100; + plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); + if( plink_freelist==0 ){ + fprintf(stderr, + "Unable to allocate memory for a new follow-set propagation link.\n"); + exit(1); + } + for(i=0; inext; + return new; +} + +/* Add a plink to a plink list */ +void Plink_add(plpp,cfp) +struct plink **plpp; +struct config *cfp; +{ + struct plink *new; + new = Plink_new(); + new->next = *plpp; + *plpp = new; + new->cfp = cfp; +} + +/* Transfer every plink on the list "from" to the list "to" */ +void Plink_copy(to,from) +struct plink **to; +struct plink *from; +{ + struct plink *nextpl; + while( from ){ + nextpl = from->next; + from->next = *to; + *to = from; + from = nextpl; + } +} + +/* Delete every plink on the list */ +void Plink_delete(plp) +struct plink *plp; +{ + struct plink *nextpl; + + while( plp ){ + nextpl = plp->next; + plp->next = plink_freelist; + plink_freelist = plp; + plp = nextpl; + } +} +/*********************** From the file "report.c" **************************/ +/* +** Procedures for generating reports and tables in the LEMON parser generator. +*/ + +/* Generate a filename with the given suffix. Space to hold the +** name comes from malloc() and must be freed by the calling +** function. +*/ +PRIVATE char *file_makename(lemp,suffix) +struct lemon *lemp; +char *suffix; +{ + char *name; + char *cp; + + name = malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); + if( name==0 ){ + fprintf(stderr,"Can't allocate space for a filename.\n"); + exit(1); + } + strcpy(name,lemp->filename); + cp = strrchr(name,'.'); + if( cp ) *cp = 0; + strcat(name,suffix); + return name; +} + +/* Open a file with a name based on the name of the input file, +** but with a different (specified) suffix, and return a pointer +** to the stream */ +PRIVATE FILE *file_open(lemp,suffix,mode) +struct lemon *lemp; +char *suffix; +char *mode; +{ + FILE *fp; + + if( lemp->outname ) free(lemp->outname); + lemp->outname = file_makename(lemp, suffix); + fp = fopen(lemp->outname,mode); + if( fp==0 && *mode=='w' ){ + fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); + lemp->errorcnt++; + return 0; + } + return fp; +} + +/* Duplicate the input file without comments and without actions +** on rules */ +void Reprint(lemp) +struct lemon *lemp; +{ + struct rule *rp; + struct symbol *sp; + int i, j, maxlen, len, ncolumns, skip; + printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); + maxlen = 10; + for(i=0; insymbol; i++){ + sp = lemp->symbols[i]; + len = lemonStrlen(sp->name); + if( len>maxlen ) maxlen = len; + } + ncolumns = 76/(maxlen+5); + if( ncolumns<1 ) ncolumns = 1; + skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; + for(i=0; insymbol; j+=skip){ + sp = lemp->symbols[j]; + assert( sp->index==j ); + printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); + } + printf("\n"); + } + for(rp=lemp->rule; rp; rp=rp->next){ + printf("%s",rp->lhs->name); + /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ + printf(" ::="); + for(i=0; inrhs; i++){ + sp = rp->rhs[i]; + printf(" %s", sp->name); + if( sp->type==MULTITERMINAL ){ + for(j=1; jnsubsym; j++){ + printf("|%s", sp->subsym[j]->name); + } + } + /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ + } + printf("."); + if( rp->precsym ) printf(" [%s]",rp->precsym->name); + /* if( rp->code ) printf("\n %s",rp->code); */ + printf("\n"); + } +} + +void ConfigPrint(fp,cfp) +FILE *fp; +struct config *cfp; +{ + struct rule *rp; + struct symbol *sp; + int i, j; + rp = cfp->rp; + fprintf(fp,"%s ::=",rp->lhs->name); + for(i=0; i<=rp->nrhs; i++){ + if( i==cfp->dot ) fprintf(fp," *"); + if( i==rp->nrhs ) break; + sp = rp->rhs[i]; + fprintf(fp," %s", sp->name); + if( sp->type==MULTITERMINAL ){ + for(j=1; jnsubsym; j++){ + fprintf(fp,"|%s",sp->subsym[j]->name); + } + } + } +} + +/* #define TEST */ +#if 0 +/* Print a set */ +PRIVATE void SetPrint(out,set,lemp) +FILE *out; +char *set; +struct lemon *lemp; +{ + int i; + char *spacer; + spacer = ""; + fprintf(out,"%12s[",""); + for(i=0; interminal; i++){ + if( SetFind(set,i) ){ + fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); + spacer = " "; + } + } + fprintf(out,"]\n"); +} + +/* Print a plink chain */ +PRIVATE void PlinkPrint(out,plp,tag) +FILE *out; +struct plink *plp; +char *tag; +{ + while( plp ){ + fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); + ConfigPrint(out,plp->cfp); + fprintf(out,"\n"); + plp = plp->next; + } +} +#endif + +/* Print an action to the given file descriptor. Return FALSE if +** nothing was actually printed. +*/ +int PrintAction(struct action *ap, FILE *fp, int indent){ + int result = 1; + switch( ap->type ){ + case SHIFT: + fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); + break; + case REDUCE: + fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); + break; + case ACCEPT: + fprintf(fp,"%*s accept",indent,ap->sp->name); + break; + case ERROR: + fprintf(fp,"%*s error",indent,ap->sp->name); + break; + case SRCONFLICT: + case RRCONFLICT: + fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", + indent,ap->sp->name,ap->x.rp->index); + break; + case SSCONFLICT: + fprintf(fp,"%*s shift %d ** Parsing conflict **", + indent,ap->sp->name,ap->x.stp->statenum); + break; + case SH_RESOLVED: + case RD_RESOLVED: + case NOT_USED: + result = 0; + break; + } + return result; +} + +/* Generate the "y.output" log file */ +void ReportOutput(lemp) +struct lemon *lemp; +{ + int i; + struct state *stp; + struct config *cfp; + struct action *ap; + FILE *fp; + + fp = file_open(lemp,".out","wb"); + if( fp==0 ) return; + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + fprintf(fp,"State %d:\n",stp->statenum); + if( lemp->basisflag ) cfp=stp->bp; + else cfp=stp->cfp; + while( cfp ){ + char buf[20]; + if( cfp->dot==cfp->rp->nrhs ){ + sprintf(buf,"(%d)",cfp->rp->index); + fprintf(fp," %5s ",buf); + }else{ + fprintf(fp," "); + } + ConfigPrint(fp,cfp); + fprintf(fp,"\n"); +#if 0 + SetPrint(fp,cfp->fws,lemp); + PlinkPrint(fp,cfp->fplp,"To "); + PlinkPrint(fp,cfp->bplp,"From"); +#endif + if( lemp->basisflag ) cfp=cfp->bp; + else cfp=cfp->next; + } + fprintf(fp,"\n"); + for(ap=stp->ap; ap; ap=ap->next){ + if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); + } + fprintf(fp,"\n"); + } + fprintf(fp, "----------------------------------------------------\n"); + fprintf(fp, "Symbols:\n"); + for(i=0; insymbol; i++){ + int j; + struct symbol *sp; + + sp = lemp->symbols[i]; + fprintf(fp, " %3d: %s", i, sp->name); + if( sp->type==NONTERMINAL ){ + fprintf(fp, ":"); + if( sp->lambda ){ + fprintf(fp, " "); + } + for(j=0; jnterminal; j++){ + if( sp->firstset && SetFind(sp->firstset, j) ){ + fprintf(fp, " %s", lemp->symbols[j]->name); + } + } + } + fprintf(fp, "\n"); + } + fclose(fp); + return; +} + +/* Search for the file "name" which is in the same directory as +** the exacutable */ +PRIVATE char *pathsearch(argv0,name,modemask) +char *argv0; +char *name; +int modemask; +{ + char *pathlist; + char *path,*cp; + char c; + +#ifdef __WIN32__ + cp = strrchr(argv0,'\\'); +#else + cp = strrchr(argv0,'/'); +#endif + if( cp ){ + c = *cp; + *cp = 0; + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); + if( path ) sprintf(path,"%s/%s",argv0,name); + *cp = c; + }else{ + extern char *getenv(); + pathlist = getenv("PATH"); + if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); + if( path!=0 ){ + while( *pathlist ){ + cp = strchr(pathlist,':'); + if( cp==0 ) cp = &pathlist[lemonStrlen(pathlist)]; + c = *cp; + *cp = 0; + sprintf(path,"%s/%s",pathlist,name); + *cp = c; + if( c==0 ) pathlist = ""; + else pathlist = &cp[1]; + if( access(path,modemask)==0 ) break; + } + } + } + return path; +} + +/* Given an action, compute the integer value for that action +** which is to be put in the action table of the generated machine. +** Return negative if no action should be generated. +*/ +PRIVATE int compute_action(lemp,ap) +struct lemon *lemp; +struct action *ap; +{ + int act; + switch( ap->type ){ + case SHIFT: act = ap->x.stp->statenum; break; + case REDUCE: act = ap->x.rp->index + lemp->nstate; break; + case ERROR: act = lemp->nstate + lemp->nrule; break; + case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; + default: act = -1; break; + } + return act; +} + +#define LINESIZE 1000 +/* The next cluster of routines are for reading the template file +** and writing the results to the generated parser */ +/* The first function transfers data from "in" to "out" until +** a line is seen which begins with "%%". The line number is +** tracked. +** +** if name!=0, then any word that begin with "Parse" is changed to +** begin with *name instead. +*/ +PRIVATE void tplt_xfer(name,in,out,lineno) +char *name; +FILE *in; +FILE *out; +int *lineno; +{ + int i, iStart; + char line[LINESIZE]; + while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ + (*lineno)++; + iStart = 0; + if( name ){ + for(i=0; line[i]; i++){ + if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 + && (i==0 || !isalpha(line[i-1])) + ){ + if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); + fprintf(out,"%s",name); + i += 4; + iStart = i+1; + } + } + } + fprintf(out,"%s",&line[iStart]); + } +} + +/* The next function finds the template file and opens it, returning +** a pointer to the opened file. */ +PRIVATE FILE *tplt_open(lemp) +struct lemon *lemp; +{ + static char templatename[] = "lempar.c"; + char buf[1000]; + FILE *in; + char *tpltname; + char *cp; + + cp = strrchr(lemp->filename,'.'); + if( cp ){ + sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); + }else{ + sprintf(buf,"%s.lt",lemp->filename); + } + if( access(buf,004)==0 ){ + tpltname = buf; + }else if( access(templatename,004)==0 ){ + tpltname = templatename; + }else{ + tpltname = pathsearch(lemp->argv0,templatename,0); + } + if( tpltname==0 ){ + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", + templatename); + lemp->errorcnt++; + return 0; + } + in = fopen(tpltname,"rb"); + if( in==0 ){ + fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); + lemp->errorcnt++; + return 0; + } + return in; +} + +/* Print a #line directive line to the output file. */ +PRIVATE void tplt_linedir(out,lineno,filename) +FILE *out; +int lineno; +char *filename; +{ + fprintf(out,"#line %d \"",lineno); + while( *filename ){ + if( *filename == '\\' ) putc('\\',out); + putc(*filename,out); + filename++; + } + fprintf(out,"\"\n"); +} + +/* Print a string to the file and keep the linenumber up to date */ +PRIVATE void tplt_print(out,lemp,str,lineno) +FILE *out; +struct lemon *lemp; +char *str; +int *lineno; +{ + if( str==0 ) return; + while( *str ){ + putc(*str,out); + if( *str=='\n' ) (*lineno)++; + str++; + } + if( str[-1]!='\n' ){ + putc('\n',out); + (*lineno)++; + } + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + return; +} + +/* +** The following routine emits code for the destructor for the +** symbol sp +*/ +void emit_destructor_code(out,sp,lemp,lineno) +FILE *out; +struct symbol *sp; +struct lemon *lemp; +int *lineno; +{ + char *cp = 0; + + if( sp->type==TERMINAL ){ + cp = lemp->tokendest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else if( sp->destructor ){ + cp = sp->destructor; + fprintf(out,"{\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } + }else if( lemp->vardest ){ + cp = lemp->vardest; + if( cp==0 ) return; + fprintf(out,"{\n"); (*lineno)++; + }else{ + assert( 0 ); /* Cannot happen */ + } + for(; *cp; cp++){ + if( *cp=='$' && cp[1]=='$' ){ + fprintf(out,"(yypminor->yy%d)",sp->dtnum); + cp++; + continue; + } + if( *cp=='\n' ) (*lineno)++; + fputc(*cp,out); + } + fprintf(out,"\n"); (*lineno)++; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + fprintf(out,"}\n"); (*lineno)++; + return; +} + +/* +** Return TRUE (non-zero) if the given symbol has a destructor. +*/ +int has_destructor(sp, lemp) +struct symbol *sp; +struct lemon *lemp; +{ + int ret; + if( sp->type==TERMINAL ){ + ret = lemp->tokendest!=0; + }else{ + ret = lemp->vardest!=0 || sp->destructor!=0; + } + return ret; +} + +/* +** Append text to a dynamically allocated string. If zText is 0 then +** reset the string to be empty again. Always return the complete text +** of the string (which is overwritten with each call). +** +** n bytes of zText are stored. If n==0 then all of zText up to the first +** \000 terminator is stored. zText can contain up to two instances of +** %d. The values of p1 and p2 are written into the first and second +** %d. +** +** If n==-1, then the previous character is overwritten. +*/ +PRIVATE char *append_str(char *zText, int n, int p1, int p2){ + static char *z = 0; + static int alloced = 0; + static int used = 0; + int c; + char zInt[40]; + + if( zText==0 ){ + used = 0; + return z; + } + if( n<=0 ){ + if( n<0 ){ + used += n; + assert( used>=0 ); + } + n = lemonStrlen(zText); + } + if( n+sizeof(zInt)*2+used >= alloced ){ + alloced = n + sizeof(zInt)*2 + used + 200; + z = realloc(z, alloced); + } + if( z==0 ) return ""; + while( n-- > 0 ){ + c = *(zText++); + if( c=='%' && n>0 && zText[0]=='d' ){ + sprintf(zInt, "%d", p1); + p1 = p2; + strcpy(&z[used], zInt); + used += lemonStrlen(&z[used]); + zText++; + n--; + }else{ + z[used++] = c; + } + } + z[used] = 0; + return z; +} + +/* +** zCode is a string that is the action associated with a rule. Expand +** the symbols in this string so that the refer to elements of the parser +** stack. +*/ +PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ + char *cp, *xp; + int i; + char lhsused = 0; /* True if the LHS element has been used */ + char used[MAXRHS]; /* True for each RHS element which is used */ + + for(i=0; inrhs; i++) used[i] = 0; + lhsused = 0; + + if( rp->code==0 ){ + rp->code = "\n"; + rp->line = rp->ruleline; + } + + append_str(0,0,0,0); + for(cp=rp->code; *cp; cp++){ + if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ + char saved; + for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); + saved = *xp; + *xp = 0; + if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ + append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); + cp = xp; + lhsused = 1; + }else{ + for(i=0; inrhs; i++){ + if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ + if( cp!=rp->code && cp[-1]=='@' ){ + /* If the argument is of the form @X then substituted + ** the token number of X, not the value of X */ + append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); + }else{ + struct symbol *sp = rp->rhs[i]; + int dtnum; + if( sp->type==MULTITERMINAL ){ + dtnum = sp->subsym[0]->dtnum; + }else{ + dtnum = sp->dtnum; + } + append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); + } + cp = xp; + used[i] = 1; + break; + } + } + } + *xp = saved; + } + append_str(cp, 1, 0, 0); + } /* End loop */ + + /* Check to make sure the LHS has been used */ + if( rp->lhsalias && !lhsused ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label \"%s\" for \"%s(%s)\" is never used.", + rp->lhsalias,rp->lhs->name,rp->lhsalias); + lemp->errorcnt++; + } + + /* Generate destructor code for RHS symbols which are not used in the + ** reduce code */ + for(i=0; inrhs; i++){ + if( rp->rhsalias[i] && !used[i] ){ + ErrorMsg(lemp->filename,rp->ruleline, + "Label %s for \"%s(%s)\" is never used.", + rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); + lemp->errorcnt++; + }else if( rp->rhsalias[i]==0 ){ + if( has_destructor(rp->rhs[i],lemp) ){ + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, + rp->rhs[i]->index,i-rp->nrhs+1); + }else{ + /* No destructor defined for this term */ + } + } + } + if( rp->code ){ + cp = append_str(0,0,0,0); + rp->code = Strsafe(cp?cp:""); + } +} + +/* +** Generate code which executes when the rule "rp" is reduced. Write +** the code to "out". Make sure lineno stays up-to-date. +*/ +PRIVATE void emit_code(out,rp,lemp,lineno) +FILE *out; +struct rule *rp; +struct lemon *lemp; +int *lineno; +{ + char *cp; + + /* Generate code to do the reduce action */ + if( rp->code ){ + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } + fprintf(out,"{%s",rp->code); + for(cp=rp->code; *cp; cp++){ + if( *cp=='\n' ) (*lineno)++; + } /* End loop */ + fprintf(out,"}\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } + } /* End if( rp->code ) */ + + return; +} + +/* +** Print the definition of the union used for the parser's data stack. +** This union contains fields for every possible data type for tokens +** and nonterminals. In the process of computing and printing this +** union, also set the ".dtnum" field of every terminal and nonterminal +** symbol. +*/ +void print_stack_union(out,lemp,plineno,mhflag) +FILE *out; /* The output stream */ +struct lemon *lemp; /* The main info structure for this parser */ +int *plineno; /* Pointer to the line number */ +int mhflag; /* True if generating makeheaders output */ +{ + int lineno = *plineno; /* The line number of the output */ + char **types; /* A hash table of datatypes */ + int arraysize; /* Size of the "types" array */ + int maxdtlength; /* Maximum length of any ".datatype" field. */ + char *stddt; /* Standardized name for a datatype */ + int i,j; /* Loop counters */ + int hash; /* For hashing the name of a type */ + char *name; /* Name of the parser */ + + /* Allocate and initialize types[] and allocate stddt[] */ + arraysize = lemp->nsymbol * 2; + types = (char**)calloc( arraysize, sizeof(char*) ); + for(i=0; ivartype ){ + maxdtlength = lemonStrlen(lemp->vartype); + } + for(i=0; insymbol; i++){ + int len; + struct symbol *sp = lemp->symbols[i]; + if( sp->datatype==0 ) continue; + len = lemonStrlen(sp->datatype); + if( len>maxdtlength ) maxdtlength = len; + } + stddt = (char*)malloc( maxdtlength*2 + 1 ); + if( types==0 || stddt==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + + /* Build a hash table of datatypes. The ".dtnum" field of each symbol + ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is + ** used for terminal symbols. If there is no %default_type defined then + ** 0 is also used as the .dtnum value for nonterminals which do not specify + ** a datatype using the %type directive. + */ + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + char *cp; + if( sp==lemp->errsym ){ + sp->dtnum = arraysize+1; + continue; + } + if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ + sp->dtnum = 0; + continue; + } + cp = sp->datatype; + if( cp==0 ) cp = lemp->vartype; + j = 0; + while( isspace(*cp) ) cp++; + while( *cp ) stddt[j++] = *cp++; + while( j>0 && isspace(stddt[j-1]) ) j--; + stddt[j] = 0; + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ + sp->dtnum = 0; + continue; + } + hash = 0; + for(j=0; stddt[j]; j++){ + hash = hash*53 + stddt[j]; + } + hash = (hash & 0x7fffffff)%arraysize; + while( types[hash] ){ + if( strcmp(types[hash],stddt)==0 ){ + sp->dtnum = hash + 1; + break; + } + hash++; + if( hash>=arraysize ) hash = 0; + } + if( types[hash]==0 ){ + sp->dtnum = hash + 1; + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); + if( types[hash]==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } + strcpy(types[hash],stddt); + } + } + + /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ + name = lemp->name ? lemp->name : "Parse"; + lineno = *plineno; + if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } + fprintf(out,"#define %sTOKENTYPE %s\n",name, + lemp->tokentype?lemp->tokentype:"void*"); lineno++; + if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } + fprintf(out,"typedef union {\n"); lineno++; + fprintf(out," int yyinit;\n"); lineno++; + fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; + for(i=0; ierrsym->useCnt ){ + fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; + } + free(stddt); + free(types); + fprintf(out,"} YYMINORTYPE;\n"); lineno++; + *plineno = lineno; +} + +/* +** Return the name of a C datatype able to represent values between +** lwr and upr, inclusive. +*/ +static const char *minimum_size_type(int lwr, int upr){ + if( lwr>=0 ){ + if( upr<=255 ){ + return "unsigned char"; + }else if( upr<65535 ){ + return "unsigned short int"; + }else{ + return "unsigned int"; + } + }else if( lwr>=-127 && upr<=127 ){ + return "signed char"; + }else if( lwr>=-32767 && upr<32767 ){ + return "short"; + }else{ + return "int"; + } +} + +/* +** Each state contains a set of token transaction and a set of +** nonterminal transactions. Each of these sets makes an instance +** of the following structure. An array of these structures is used +** to order the creation of entries in the yy_action[] table. +*/ +struct axset { + struct state *stp; /* A pointer to a state */ + int isTkn; /* True to use tokens. False for non-terminals */ + int nAction; /* Number of actions */ +}; + +/* +** Compare to axset structures for sorting purposes +*/ +static int axset_compare(const void *a, const void *b){ + struct axset *p1 = (struct axset*)a; + struct axset *p2 = (struct axset*)b; + return p2->nAction - p1->nAction; +} + +/* +** Write text on "out" that describes the rule "rp". +*/ +static void writeRuleText(FILE *out, struct rule *rp){ + int j; + fprintf(out,"%s ::=", rp->lhs->name); + for(j=0; jnrhs; j++){ + struct symbol *sp = rp->rhs[j]; + fprintf(out," %s", sp->name); + if( sp->type==MULTITERMINAL ){ + int k; + for(k=1; knsubsym; k++){ + fprintf(out,"|%s",sp->subsym[k]->name); + } + } + } +} + + +/* Generate C source code for the parser */ +void ReportTable(lemp, mhflag) +struct lemon *lemp; +int mhflag; /* Output in makeheaders format if true */ +{ + FILE *out, *in; + char line[LINESIZE]; + int lineno; + struct state *stp; + struct action *ap; + struct rule *rp; + struct acttab *pActtab; + int i, j, n; + char *name; + int mnTknOfst, mxTknOfst; + int mnNtOfst, mxNtOfst; + struct axset *ax; + + in = tplt_open(lemp); + if( in==0 ) return; + out = file_open(lemp,".c","wb"); + if( out==0 ){ + fclose(in); + return; + } + lineno = 1; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the include code, if any */ + tplt_print(out,lemp,lemp->include,&lineno); + if( mhflag ){ + char *name = file_makename(lemp, ".h"); + fprintf(out,"#include \"%s\"\n", name); lineno++; + free(name); + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate #defines for all tokens */ + if( mhflag ){ + char *prefix; + fprintf(out,"#if INTERFACE\n"); lineno++; + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + for(i=1; interminal; i++){ + fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + lineno++; + } + fprintf(out,"#endif\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the defines */ + fprintf(out,"#define YYCODETYPE %s\n", + minimum_size_type(0, lemp->nsymbol+1)); lineno++; + fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; + fprintf(out,"#define YYACTIONTYPE %s\n", + minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; + if( lemp->wildcard ){ + fprintf(out,"#define YYWILDCARD %d\n", + lemp->wildcard->index); lineno++; + } + print_stack_union(out,lemp,&lineno,mhflag); + fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++; + if( lemp->stacksize ){ + fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; + }else{ + fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; + } + fprintf(out, "#endif\n"); lineno++; + if( mhflag ){ + fprintf(out,"#if INTERFACE\n"); lineno++; + } + name = lemp->name ? lemp->name : "Parse"; + if( lemp->arg && lemp->arg[0] ){ + int i; + i = lemonStrlen(lemp->arg); + while( i>=1 && isspace(lemp->arg[i-1]) ) i--; + while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; + fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; + fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", + name,lemp->arg,&lemp->arg[i]); lineno++; + fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", + name,&lemp->arg[i],&lemp->arg[i]); lineno++; + }else{ + fprintf(out,"#define %sARG_SDECL\n",name); lineno++; + fprintf(out,"#define %sARG_PDECL\n",name); lineno++; + fprintf(out,"#define %sARG_FETCH\n",name); lineno++; + fprintf(out,"#define %sARG_STORE\n",name); lineno++; + } + if( mhflag ){ + fprintf(out,"#endif\n"); lineno++; + } + fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; + fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; + if( lemp->errsym->useCnt ){ + fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; + fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; + } + if( lemp->has_fallback ){ + fprintf(out,"#define YYFALLBACK 1\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the action table and its associates: + ** + ** yy_action[] A single table containing all actions. + ** yy_lookahead[] A table containing the lookahead for each entry in + ** yy_action. Used to detect hash collisions. + ** yy_shift_ofst[] For each state, the offset into yy_action for + ** shifting terminals. + ** yy_reduce_ofst[] For each state, the offset into yy_action for + ** shifting non-terminals after a reduce. + ** yy_default[] Default action for each state. + */ + + /* Compute the actions on all states and count them up */ + ax = calloc(lemp->nstate*2, sizeof(ax[0])); + if( ax==0 ){ + fprintf(stderr,"malloc failed\n"); + exit(1); + } + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + ax[i*2].stp = stp; + ax[i*2].isTkn = 1; + ax[i*2].nAction = stp->nTknAct; + ax[i*2+1].stp = stp; + ax[i*2+1].isTkn = 0; + ax[i*2+1].nAction = stp->nNtAct; + } + mxTknOfst = mnTknOfst = 0; + mxNtOfst = mnNtOfst = 0; + + /* Compute the action table. In order to try to keep the size of the + ** action table to a minimum, the heuristic of placing the largest action + ** sets first is used. + */ + qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); + pActtab = acttab_alloc(); + for(i=0; instate*2 && ax[i].nAction>0; i++){ + stp = ax[i].stp; + if( ax[i].isTkn ){ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->index>=lemp->nterminal ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iTknOfst = acttab_insert(pActtab); + if( stp->iTknOfstiTknOfst; + if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; + }else{ + for(ap=stp->ap; ap; ap=ap->next){ + int action; + if( ap->sp->indexnterminal ) continue; + if( ap->sp->index==lemp->nsymbol ) continue; + action = compute_action(lemp, ap); + if( action<0 ) continue; + acttab_action(pActtab, ap->sp->index, action); + } + stp->iNtOfst = acttab_insert(pActtab); + if( stp->iNtOfstiNtOfst; + if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; + } + } + free(ax); + + /* Output the yy_action table */ + fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; + n = acttab_size(pActtab); + for(i=j=0; instate + lemp->nrule + 2; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", action); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_lookahead table */ + fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; + for(i=j=0; insymbol; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", la); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_shift_ofst[] table */ + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++; + fprintf(out, "static const %s yy_shift_ofst[] = {\n", + minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; + for(i=j=0; isorted[i]; + ofst = stp->iTknOfst; + if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the yy_reduce_ofst[] table */ + fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; + n = lemp->nstate; + while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; + fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++; + fprintf(out, "static const %s yy_reduce_ofst[] = {\n", + minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; + for(i=j=0; isorted[i]; + ofst = stp->iNtOfst; + if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", ofst); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + + /* Output the default action table */ + fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; + n = lemp->nstate; + for(i=j=0; isorted[i]; + if( j==0 ) fprintf(out," /* %5d */ ", i); + fprintf(out, " %4d,", stp->iDflt); + if( j==9 || i==n-1 ){ + fprintf(out, "\n"); lineno++; + j = 0; + }else{ + j++; + } + } + fprintf(out, "};\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of fallback tokens. + */ + if( lemp->has_fallback ){ + int mx = lemp->nterminal - 1; + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + for(i=0; i<=mx; i++){ + struct symbol *p = lemp->symbols[i]; + if( p->fallback==0 ){ + fprintf(out, " 0, /* %10s => nothing */\n", p->name); + }else{ + fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, + p->name, p->fallback->name); + } + lineno++; + } + } + tplt_xfer(lemp->name, in, out, &lineno); + + /* Generate a table containing the symbolic name of every symbol + */ + for(i=0; insymbol; i++){ + sprintf(line,"\"%s\",",lemp->symbols[i]->name); + fprintf(out," %-15s",line); + if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } + } + if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate a table containing a text string that describes every + ** rule in the rule set of the grammar. This information is used + ** when tracing REDUCE actions. + */ + for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ + assert( rp->index==i ); + fprintf(out," /* %3d */ \"", i); + writeRuleText(out, rp); + fprintf(out,"\",\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes every time a symbol is popped from + ** the stack while processing errors or while destroying the parser. + ** (In other words, generate the %destructor actions) + */ + if( lemp->tokendest ){ + int once = 1; + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type!=TERMINAL ) continue; + if( once ){ + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + } + for(i=0; insymbol && lemp->symbols[i]->type!=TERMINAL; i++); + if( insymbol ){ + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + } + if( lemp->vardest ){ + struct symbol *dflt_sp = 0; + int once = 1; + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || + sp->index<=0 || sp->destructor!=0 ) continue; + if( once ){ + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + dflt_sp = sp; + } + if( dflt_sp!=0 ){ + emit_destructor_code(out,dflt_sp,lemp,&lineno); + } + fprintf(out," break;\n"); lineno++; + } + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; + + /* Combine duplicate destructors into a single case */ + for(j=i+1; jnsymbol; j++){ + struct symbol *sp2 = lemp->symbols[j]; + if( sp2 && sp2->type!=TERMINAL && sp2->destructor + && sp2->dtnum==sp->dtnum + && strcmp(sp->destructor,sp2->destructor)==0 ){ + fprintf(out," case %d: /* %s */\n", + sp2->index, sp2->name); lineno++; + sp2->destructor = 0; + } + } + + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes whenever the parser stack overflows */ + tplt_print(out,lemp,lemp->overflow,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate the table of rule information + ** + ** Note: This code depends on the fact that rules are number + ** sequentually beginning with 0. + */ + for(rp=lemp->rule; rp; rp=rp->next){ + fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; + } + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which execution during each REDUCE action */ + for(rp=lemp->rule; rp; rp=rp->next){ + translate_code(lemp, rp); + } + /* First output rules other than the default: rule */ + for(rp=lemp->rule; rp; rp=rp->next){ + struct rule *rp2; /* Other rules with the same action */ + if( rp->code==0 ) continue; + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ + fprintf(out," case %d: /* ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */\n"); lineno++; + for(rp2=rp->next; rp2; rp2=rp2->next){ + if( rp2->code==rp->code ){ + fprintf(out," case %d: /* ", rp2->index); + writeRuleText(out, rp2); + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; + rp2->code = 0; + } + } + emit_code(out,rp,lemp,&lineno); + fprintf(out," break;\n"); lineno++; + rp->code = 0; + } + /* Finally, output the default: rule. We choose as the default: all + ** empty actions. */ + fprintf(out," default:\n"); lineno++; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->code==0 ) continue; + assert( rp->code[0]=='\n' && rp->code[1]==0 ); + fprintf(out," /* (%d) ", rp->index); + writeRuleText(out, rp); + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + } + fprintf(out," break;\n"); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes if a parse fails */ + tplt_print(out,lemp,lemp->failure,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when a syntax error occurs */ + tplt_print(out,lemp,lemp->error,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Generate code which executes when the parser accepts its input */ + tplt_print(out,lemp,lemp->accept,&lineno); + tplt_xfer(lemp->name,in,out,&lineno); + + /* Append any addition code the user desires */ + tplt_print(out,lemp,lemp->extracode,&lineno); + + fclose(in); + fclose(out); + return; +} + +/* Generate a header file for the parser */ +void ReportHeader(lemp) +struct lemon *lemp; +{ + FILE *out, *in; + char *prefix; + char line[LINESIZE]; + char pattern[LINESIZE]; + int i; + + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; + else prefix = ""; + in = file_open(lemp,".h","rb"); + if( in ){ + for(i=1; interminal && fgets(line,LINESIZE,in); i++){ + sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + if( strcmp(line,pattern) ) break; + } + fclose(in); + if( i==lemp->nterminal ){ + /* No change in the file. Don't rewrite it. */ + return; + } + } + out = file_open(lemp,".h","wb"); + if( out ){ + for(i=1; interminal; i++){ + fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + } + fclose(out); + } + return; +} + +/* Reduce the size of the action tables, if possible, by making use +** of defaults. +** +** In this version, we take the most frequent REDUCE action and make +** it the default. Except, there is no default if the wildcard token +** is a possible look-ahead. +*/ +void CompressTables(lemp) +struct lemon *lemp; +{ + struct state *stp; + struct action *ap, *ap2; + struct rule *rp, *rp2, *rbest; + int nbest, n; + int i; + int usesWildcard; + + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + nbest = 0; + rbest = 0; + usesWildcard = 0; + + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ + usesWildcard = 1; + } + if( ap->type!=REDUCE ) continue; + rp = ap->x.rp; + if( rp->lhsStart ) continue; + if( rp==rbest ) continue; + n = 1; + for(ap2=ap->next; ap2; ap2=ap2->next){ + if( ap2->type!=REDUCE ) continue; + rp2 = ap2->x.rp; + if( rp2==rbest ) continue; + if( rp2==rp ) n++; + } + if( n>nbest ){ + nbest = n; + rbest = rp; + } + } + + /* Do not make a default if the number of rules to default + ** is not at least 1 or if the wildcard token is a possible + ** lookahead. + */ + if( nbest<1 || usesWildcard ) continue; + + + /* Combine matching REDUCE actions into a single default */ + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) break; + } + assert( ap ); + ap->sp = Symbol_new("{default}"); + for(ap=ap->next; ap; ap=ap->next){ + if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; + } + stp->ap = Action_sort(stp->ap); + } +} + + +/* +** Compare two states for sorting purposes. The smaller state is the +** one with the most non-terminal actions. If they have the same number +** of non-terminal actions, then the smaller is the one with the most +** token actions. +*/ +static int stateResortCompare(const void *a, const void *b){ + const struct state *pA = *(const struct state**)a; + const struct state *pB = *(const struct state**)b; + int n; + + n = pB->nNtAct - pA->nNtAct; + if( n==0 ){ + n = pB->nTknAct - pA->nTknAct; + } + return n; +} + + +/* +** Renumber and resort states so that states with fewer choices +** occur at the end. Except, keep state 0 as the first state. +*/ +void ResortStates(lemp) +struct lemon *lemp; +{ + int i; + struct state *stp; + struct action *ap; + + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + stp->nTknAct = stp->nNtAct = 0; + stp->iDflt = lemp->nstate + lemp->nrule; + stp->iTknOfst = NO_OFFSET; + stp->iNtOfst = NO_OFFSET; + for(ap=stp->ap; ap; ap=ap->next){ + if( compute_action(lemp,ap)>=0 ){ + if( ap->sp->indexnterminal ){ + stp->nTknAct++; + }else if( ap->sp->indexnsymbol ){ + stp->nNtAct++; + }else{ + stp->iDflt = compute_action(lemp, ap); + } + } + } + } + qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), + stateResortCompare); + for(i=0; instate; i++){ + lemp->sorted[i]->statenum = i; + } +} + + +/***************** From the file "set.c" ************************************/ +/* +** Set manipulation routines for the LEMON parser generator. +*/ + +static int size = 0; + +/* Set the set size */ +void SetSize(n) +int n; +{ + size = n+1; +} + +/* Allocate a new set */ +char *SetNew(){ + char *s; + s = (char*)calloc( size, 1); + if( s==0 ){ + extern void memory_error(); + memory_error(); + } + return s; +} + +/* Deallocate a set */ +void SetFree(s) +char *s; +{ + free(s); +} + +/* Add a new element to the set. Return TRUE if the element was added +** and FALSE if it was already there. */ +int SetAdd(s,e) +char *s; +int e; +{ + int rv; + assert( e>=0 && esize = 1024; + x1a->count = 0; + x1a->tbl = (x1node*)malloc( + (sizeof(x1node) + sizeof(x1node*))*1024 ); + if( x1a->tbl==0 ){ + free(x1a); + x1a = 0; + }else{ + int i; + x1a->ht = (x1node**)&(x1a->tbl[1024]); + for(i=0; i<1024; i++) x1a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Strsafe_insert(data) +char *data; +{ + x1node *np; + int h; + int ph; + + if( x1a==0 ) return 0; + ph = strhash(data); + h = ph & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x1a->count>=x1a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x1 array; + array.size = size = x1a->size*2; + array.count = x1a->count; + array.tbl = (x1node*)malloc( + (sizeof(x1node) + sizeof(x1node*))*size ); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x1node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x1node *oldnp, *newnp; + oldnp = &(x1a->tbl[i]); + h = strhash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x1a->tbl); + *x1a = array; + } + /* Insert the new data */ + h = ph & (x1a->size-1); + np = &(x1a->tbl[x1a->count++]); + np->data = data; + if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); + np->next = x1a->ht[h]; + x1a->ht[h] = np; + np->from = &(x1a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +char *Strsafe_find(key) +char *key; +{ + int h; + x1node *np; + + if( x1a==0 ) return 0; + h = strhash(key) & (x1a->size-1); + np = x1a->ht[h]; + while( np ){ + if( strcmp(np->data,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return a pointer to the (terminal or nonterminal) symbol "x". +** Create a new symbol if this is the first time "x" has been seen. +*/ +struct symbol *Symbol_new(x) +char *x; +{ + struct symbol *sp; + + sp = Symbol_find(x); + if( sp==0 ){ + sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); + MemoryCheck(sp); + sp->name = Strsafe(x); + sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; + sp->rule = 0; + sp->fallback = 0; + sp->prec = -1; + sp->assoc = UNK; + sp->firstset = 0; + sp->lambda = LEMON_FALSE; + sp->destructor = 0; + sp->destLineno = 0; + sp->datatype = 0; + sp->useCnt = 0; + Symbol_insert(sp,sp->name); + } + sp->useCnt++; + return sp; +} + +/* Compare two symbols for working purposes +** +** Symbols that begin with upper case letters (terminals or tokens) +** must sort before symbols that begin with lower case letters +** (non-terminals). Other than that, the order does not matter. +** +** We find experimentally that leaving the symbols in their original +** order (the order they appeared in the grammar file) gives the +** smallest parser tables in SQLite. +*/ +int Symbolcmpp(struct symbol **a, struct symbol **b){ + int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); + int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); + return i1-i2; +} + +/* There is one instance of the following structure for each +** associative array of type "x2". +*/ +struct s_x2 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x2node *tbl; /* The data stored here */ + struct s_x2node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x2". +*/ +typedef struct s_x2node { + struct symbol *data; /* The data */ + char *key; /* The key */ + struct s_x2node *next; /* Next entry with the same hash */ + struct s_x2node **from; /* Previous link */ +} x2node; + +/* There is only one instance of the array, which is the following */ +static struct s_x2 *x2a; + +/* Allocate a new associative array */ +void Symbol_init(){ + if( x2a ) return; + x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); + if( x2a ){ + x2a->size = 128; + x2a->count = 0; + x2a->tbl = (x2node*)malloc( + (sizeof(x2node) + sizeof(x2node*))*128 ); + if( x2a->tbl==0 ){ + free(x2a); + x2a = 0; + }else{ + int i; + x2a->ht = (x2node**)&(x2a->tbl[128]); + for(i=0; i<128; i++) x2a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Symbol_insert(data,key) +struct symbol *data; +char *key; +{ + x2node *np; + int h; + int ph; + + if( x2a==0 ) return 0; + ph = strhash(key); + h = ph & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x2a->count>=x2a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x2 array; + array.size = size = x2a->size*2; + array.count = x2a->count; + array.tbl = (x2node*)malloc( + (sizeof(x2node) + sizeof(x2node*))*size ); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x2node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x2node *oldnp, *newnp; + oldnp = &(x2a->tbl[i]); + h = strhash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x2a->tbl); + *x2a = array; + } + /* Insert the new data */ + h = ph & (x2a->size-1); + np = &(x2a->tbl[x2a->count++]); + np->key = key; + np->data = data; + if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); + np->next = x2a->ht[h]; + x2a->ht[h] = np; + np->from = &(x2a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct symbol *Symbol_find(key) +char *key; +{ + int h; + x2node *np; + + if( x2a==0 ) return 0; + h = strhash(key) & (x2a->size-1); + np = x2a->ht[h]; + while( np ){ + if( strcmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return the n-th data. Return NULL if n is out of range. */ +struct symbol *Symbol_Nth(n) +int n; +{ + struct symbol *data; + if( x2a && n>0 && n<=x2a->count ){ + data = x2a->tbl[n-1].data; + }else{ + data = 0; + } + return data; +} + +/* Return the size of the array */ +int Symbol_count() +{ + return x2a ? x2a->count : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct symbol **Symbol_arrayof() +{ + struct symbol **array; + int i,size; + if( x2a==0 ) return 0; + size = x2a->count; + array = (struct symbol **)calloc(size, sizeof(struct symbol *)); + if( array ){ + for(i=0; itbl[i].data; + } + return array; +} + +/* Compare two configurations */ +int Configcmp(a,b) +struct config *a; +struct config *b; +{ + int x; + x = a->rp->index - b->rp->index; + if( x==0 ) x = a->dot - b->dot; + return x; +} + +/* Compare two states */ +PRIVATE int statecmp(a,b) +struct config *a; +struct config *b; +{ + int rc; + for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ + rc = a->rp->index - b->rp->index; + if( rc==0 ) rc = a->dot - b->dot; + } + if( rc==0 ){ + if( a ) rc = 1; + if( b ) rc = -1; + } + return rc; +} + +/* Hash a state */ +PRIVATE int statehash(a) +struct config *a; +{ + int h=0; + while( a ){ + h = h*571 + a->rp->index*37 + a->dot; + a = a->bp; + } + return h; +} + +/* Allocate a new state structure */ +struct state *State_new() +{ + struct state *new; + new = (struct state *)calloc(1, sizeof(struct state) ); + MemoryCheck(new); + return new; +} + +/* There is one instance of the following structure for each +** associative array of type "x3". +*/ +struct s_x3 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x3node *tbl; /* The data stored here */ + struct s_x3node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x3". +*/ +typedef struct s_x3node { + struct state *data; /* The data */ + struct config *key; /* The key */ + struct s_x3node *next; /* Next entry with the same hash */ + struct s_x3node **from; /* Previous link */ +} x3node; + +/* There is only one instance of the array, which is the following */ +static struct s_x3 *x3a; + +/* Allocate a new associative array */ +void State_init(){ + if( x3a ) return; + x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); + if( x3a ){ + x3a->size = 128; + x3a->count = 0; + x3a->tbl = (x3node*)malloc( + (sizeof(x3node) + sizeof(x3node*))*128 ); + if( x3a->tbl==0 ){ + free(x3a); + x3a = 0; + }else{ + int i; + x3a->ht = (x3node**)&(x3a->tbl[128]); + for(i=0; i<128; i++) x3a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int State_insert(data,key) +struct state *data; +struct config *key; +{ + x3node *np; + int h; + int ph; + + if( x3a==0 ) return 0; + ph = statehash(key); + h = ph & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x3a->count>=x3a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x3 array; + array.size = size = x3a->size*2; + array.count = x3a->count; + array.tbl = (x3node*)malloc( + (sizeof(x3node) + sizeof(x3node*))*size ); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x3node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x3node *oldnp, *newnp; + oldnp = &(x3a->tbl[i]); + h = statehash(oldnp->key) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->key = oldnp->key; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x3a->tbl); + *x3a = array; + } + /* Insert the new data */ + h = ph & (x3a->size-1); + np = &(x3a->tbl[x3a->count++]); + np->key = key; + np->data = data; + if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); + np->next = x3a->ht[h]; + x3a->ht[h] = np; + np->from = &(x3a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct state *State_find(key) +struct config *key; +{ + int h; + x3node *np; + + if( x3a==0 ) return 0; + h = statehash(key) & (x3a->size-1); + np = x3a->ht[h]; + while( np ){ + if( statecmp(np->key,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Return an array of pointers to all data in the table. +** The array is obtained from malloc. Return NULL if memory allocation +** problems, or if the array is empty. */ +struct state **State_arrayof() +{ + struct state **array; + int i,size; + if( x3a==0 ) return 0; + size = x3a->count; + array = (struct state **)malloc( sizeof(struct state *)*size ); + if( array ){ + for(i=0; itbl[i].data; + } + return array; +} + +/* Hash a configuration */ +PRIVATE int confighash(a) +struct config *a; +{ + int h=0; + h = h*571 + a->rp->index*37 + a->dot; + return h; +} + +/* There is one instance of the following structure for each +** associative array of type "x4". +*/ +struct s_x4 { + int size; /* The number of available slots. */ + /* Must be a power of 2 greater than or */ + /* equal to 1 */ + int count; /* Number of currently slots filled */ + struct s_x4node *tbl; /* The data stored here */ + struct s_x4node **ht; /* Hash table for lookups */ +}; + +/* There is one instance of this structure for every data element +** in an associative array of type "x4". +*/ +typedef struct s_x4node { + struct config *data; /* The data */ + struct s_x4node *next; /* Next entry with the same hash */ + struct s_x4node **from; /* Previous link */ +} x4node; + +/* There is only one instance of the array, which is the following */ +static struct s_x4 *x4a; + +/* Allocate a new associative array */ +void Configtable_init(){ + if( x4a ) return; + x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); + if( x4a ){ + x4a->size = 64; + x4a->count = 0; + x4a->tbl = (x4node*)malloc( + (sizeof(x4node) + sizeof(x4node*))*64 ); + if( x4a->tbl==0 ){ + free(x4a); + x4a = 0; + }else{ + int i; + x4a->ht = (x4node**)&(x4a->tbl[64]); + for(i=0; i<64; i++) x4a->ht[i] = 0; + } + } +} +/* Insert a new record into the array. Return TRUE if successful. +** Prior data with the same key is NOT overwritten */ +int Configtable_insert(data) +struct config *data; +{ + x4node *np; + int h; + int ph; + + if( x4a==0 ) return 0; + ph = confighash(data); + h = ph & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp(np->data,data)==0 ){ + /* An existing entry with the same key is found. */ + /* Fail because overwrite is not allows. */ + return 0; + } + np = np->next; + } + if( x4a->count>=x4a->size ){ + /* Need to make the hash table bigger */ + int i,size; + struct s_x4 array; + array.size = size = x4a->size*2; + array.count = x4a->count; + array.tbl = (x4node*)malloc( + (sizeof(x4node) + sizeof(x4node*))*size ); + if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ + array.ht = (x4node**)&(array.tbl[size]); + for(i=0; icount; i++){ + x4node *oldnp, *newnp; + oldnp = &(x4a->tbl[i]); + h = confighash(oldnp->data) & (size-1); + newnp = &(array.tbl[i]); + if( array.ht[h] ) array.ht[h]->from = &(newnp->next); + newnp->next = array.ht[h]; + newnp->data = oldnp->data; + newnp->from = &(array.ht[h]); + array.ht[h] = newnp; + } + free(x4a->tbl); + *x4a = array; + } + /* Insert the new data */ + h = ph & (x4a->size-1); + np = &(x4a->tbl[x4a->count++]); + np->data = data; + if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); + np->next = x4a->ht[h]; + x4a->ht[h] = np; + np->from = &(x4a->ht[h]); + return 1; +} + +/* Return a pointer to data assigned to the given key. Return NULL +** if no such key. */ +struct config *Configtable_find(key) +struct config *key; +{ + int h; + x4node *np; + + if( x4a==0 ) return 0; + h = confighash(key) & (x4a->size-1); + np = x4a->ht[h]; + while( np ){ + if( Configcmp(np->data,key)==0 ) break; + np = np->next; + } + return np ? np->data : 0; +} + +/* Remove all data from the table. Pass each data to the function "f" +** as it is removed. ("f" may be null to avoid this step.) */ +void Configtable_clear(f) +int(*f)(/* struct config * */); +{ + int i; + if( x4a==0 || x4a->count==0 ) return; + if( f ) for(i=0; icount; i++) (*f)(x4a->tbl[i].data); + for(i=0; isize; i++) x4a->ht[i] = 0; + x4a->count = 0; + return; +} diff --git a/sysutils/pm/lemon/lemon.txt b/sysutils/pm/lemon/lemon.txt new file mode 100644 index 0000000..3094184 --- /dev/null +++ b/sysutils/pm/lemon/lemon.txt @@ -0,0 +1,433 @@ +The Lemon Parser Generator + +Lemon is an LALR(1) parser generator for C or C++. It does the same job as ``bison'' and ``yacc''. But lemon is not another bison or yacc clone. It uses a different grammar syntax which is designed to reduce the number of coding errors. Lemon also uses a more sophisticated parsing engine that is faster than yacc and bison and which is both reentrant and thread-safe. Furthermore, Lemon implements features that can be used to eliminate resource leaks, making is suitable for use in long-running programs such as graphical user interfaces or embedded controllers. + +This document is an introduction to the Lemon parser generator. +Theory of Operation + +The main goal of Lemon is to translate a context free grammar (CFG) for a particular language into C code that implements a parser for that language. The program has two inputs: + + * The grammar specification. + * A parser template file. + +Typically, only the grammar specification is supplied by the programmer. Lemon comes with a default parser template which works fine for most applications. But the user is free to substitute a different parser template if desired. + +Depending on command-line options, Lemon will generate between one and three files of outputs. + + * C code to implement the parser. + * A header file defining an integer ID for each terminal symbol. + * An information file that describes the states of the generated parser automaton. + +By default, all three of these output files are generated. The header file is suppressed if the ``-m'' command-line option is used and the report file is omitted when ``-q'' is selected. + +The grammar specification file uses a ``.y'' suffix, by convention. In the examples used in this document, we'll assume the name of the grammar file is ``gram.y''. A typical use of Lemon would be the following command: + + lemon gram.y + +This command will generate three output files named ``gram.c'', ``gram.h'' and ``gram.out''. The first is C code to implement the parser. The second is the header file that defines numerical values for all terminal symbols, and the last is the report that explains the states used by the parser automaton. + +Command Line Options + +The behavior of Lemon can be modified using command-line options. You can obtain a list of the available command-line options together with a brief explanation of what each does by typing + + lemon -? + +As of this writing, the following command-line options are supported: + + * -b + * -c + * -g + * -m + * -q + * -s + * -x + +The ``-b'' option reduces the amount of text in the report file by printing only the basis of each parser state, rather than the full configuration. The ``-c'' option suppresses action table compression. Using -c will make the parser a little larger and slower but it will detect syntax errors sooner. The ``-g'' option causes no output files to be generated at all. Instead, the input grammar file is printed on standard output but with all comments, actions and other extraneous text deleted. This is a useful way to get a quick summary of a grammar. The ``-m'' option causes the output C source file to be compatible with the ``makeheaders'' program. Makeheaders is a program that automatically generates header files from C source code. When the ``-m'' option is used, the header file is not output since the makeheaders program will take care of generated all header files automatically. The ``-q'' option suppresses the report file. Using ``-s'' causes a brief summary of parser statistics to be printed. Like this: + + Parser statistics: 74 terminals, 70 nonterminals, 179 rules + 340 states, 2026 parser table entries, 0 conflicts + +Finally, the ``-x'' option causes Lemon to print its version number and copyright information and then stop without attempting to read the grammar or generate a parser. + +The Parser Interface + +Lemon doesn't generate a complete, working program. It only generates a few subroutines that implement a parser. This section describes the interface to those subroutines. It is up to the programmer to call these subroutines in an appropriate way in order to produce a complete system. + +Before a program begins using a Lemon-generated parser, the program must first create the parser. A new parser is created as follows: + + void *pParser = ParseAlloc( malloc ); + +The ParseAlloc() routine allocates and initializes a new parser and returns a pointer to it. The actual data structure used to represent a parser is opaque -- its internal structure is not visible or usable by the calling routine. For this reason, the ParseAlloc() routine returns a pointer to void rather than a pointer to some particular structure. The sole argument to the ParseAlloc() routine is a pointer to the subroutine used to allocate memory. Typically this means ``malloc()''. + +After a program is finished using a parser, it can reclaim all memory allocated by that parser by calling + + ParseFree(pParser, free); + +The first argument is the same pointer returned by ParseAlloc(). The second argument is a pointer to the function used to release bulk memory back to the system. + +After a parser has been allocated using ParseAlloc(), the programmer must supply the parser with a sequence of tokens (terminal symbols) to be parsed. This is accomplished by calling the following function once for each token: + + Parse(pParser, hTokenID, sTokenData, pArg); + +The first argument to the Parse() routine is the pointer returned by ParseAlloc(). The second argument is a small positive integer that tells the parse the type of the next token in the data stream. There is one token type for each terminal symbol in the grammar. The gram.h file generated by Lemon contains #define statements that map symbolic terminal symbol names into appropriate integer values. (A value of 0 for the second argument is a special flag to the parser to indicate that the end of input has been reached.) The third argument is the value of the given token. By default, the type of the third argument is integer, but the grammar will usually redefine this type to be some kind of structure. Typically the second argument will be a broad category of tokens such as ``identifier'' or ``number'' and the third argument will be the name of the identifier or the value of the number. + +The Parse() function may have either three or four arguments, depending on the grammar. If the grammar specification file request it, the Parse() function will have a fourth parameter that can be of any type chosen by the programmer. The parser doesn't do anything with this argument except to pass it through to action routines. This is a convenient mechanism for passing state information down to the action routines without having to use global variables. + +A typical use of a Lemon parser might look something like the following: + + 01 ParseTree *ParseFile(const char *zFilename){ + 02 Tokenizer *pTokenizer; + 03 void *pParser; + 04 Token sToken; + 05 int hTokenId; + 06 ParserState sState; + 07 + 08 pTokenizer = TokenizerCreate(zFilename); + 09 pParser = ParseAlloc( malloc ); + 10 InitParserState(&sState); + 11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){ + 12 Parse(pParser, hTokenId, sToken, &sState); + 13 } + 14 Parse(pParser, 0, sToken, &sState); + 15 ParseFree(pParser, free ); + 16 TokenizerFree(pTokenizer); + 17 return sState.treeRoot; + 18 } + +This example shows a user-written routine that parses a file of text and returns a pointer to the parse tree. (We've omitted all error-handling from this example to keep it simple.) We assume the existence of some kind of tokenizer which is created using TokenizerCreate() on line 8 and deleted by TokenizerFree() on line 16. The GetNextToken() function on line 11 retrieves the next token from the input file and puts its type in the integer variable hTokenId. The sToken variable is assumed to be some kind of structure that contains details about each token, such as its complete text, what line it occurs on, etc. + +This example also assumes the existence of structure of type ParserState that holds state information about a particular parse. An instance of such a structure is created on line 6 and initialized on line 10. A pointer to this structure is passed into the Parse() routine as the optional 4th argument. The action routine specified by the grammar for the parser can use the ParserState structure to hold whatever information is useful and appropriate. In the example, we note that the treeRoot field of the ParserState structure is left pointing to the root of the parse tree. + +The core of this example as it relates to Lemon is as follows: + + ParseFile(){ + pParser = ParseAlloc( malloc ); + while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){ + Parse(pParser, hTokenId, sToken); + } + Parse(pParser, 0, sToken); + ParseFree(pParser, free ); + } + +Basically, what a program has to do to use a Lemon-generated parser is first create the parser, then send it lots of tokens obtained by tokenizing an input source. When the end of input is reached, the Parse() routine should be called one last time with a token type of 0. This step is necessary to inform the parser that the end of input has been reached. Finally, we reclaim memory used by the parser by calling ParseFree(). + +There is one other interface routine that should be mentioned before we move on. The ParseTrace() function can be used to generate debugging output from the parser. A prototype for this routine is as follows: + + ParseTrace(FILE *stream, char *zPrefix); + +After this routine is called, a short (one-line) message is written to the designated output stream every time the parser changes states or calls an action routine. Each such message is prefaced using the text given by zPrefix. This debugging output can be turned off by calling ParseTrace() again with a first argument of NULL (0). + +Differences With YACC and BISON + +Programmers who have previously used the yacc or bison parser generator will notice several important differences between yacc and/or bison and Lemon. + + * In yacc and bison, the parser calls the tokenizer. In Lemon, the tokenizer calls the parser. + * Lemon uses no global variables. Yacc and bison use global variables to pass information between the tokenizer and parser. + * Lemon allows multiple parsers to be running simultaneously. Yacc and bison do not. + +These differences may cause some initial confusion for programmers with prior yacc and bison experience. But after years of experience using Lemon, I firmly believe that the Lemon way of doing things is better. + +Input File Syntax + +The main purpose of the grammar specification file for Lemon is to define the grammar for the parser. But the input file also specifies additional information Lemon requires to do its job. Most of the work in using Lemon is in writing an appropriate grammar file. + +The grammar file for lemon is, for the most part, free format. It does not have sections or divisions like yacc or bison. Any declaration can occur at any point in the file. Lemon ignores whitespace (except where it is needed to separate tokens) and it honors the same commenting conventions as C and C++. +Terminals and Nonterminals + +A terminal symbol (token) is any string of alphanumeric and underscore characters that begins with an upper case letter. A terminal can contain lower class letters after the first character, but the usual convention is to make terminals all upper case. A nonterminal, on the other hand, is any string of alphanumeric and underscore characters than begins with a lower case letter. Again, the usual convention is to make nonterminals use all lower case letters. + +In Lemon, terminal and nonterminal symbols do not need to be declared or identified in a separate section of the grammar file. Lemon is able to generate a list of all terminals and nonterminals by examining the grammar rules, and it can always distinguish a terminal from a nonterminal by checking the case of the first character of the name. + +Yacc and bison allow terminal symbols to have either alphanumeric names or to be individual characters included in single quotes, like this: ')' or '$'. Lemon does not allow this alternative form for terminal symbols. With Lemon, all symbols, terminals and nonterminals, must have alphanumeric names. +Grammar Rules + +The main component of a Lemon grammar file is a sequence of grammar rules. Each grammar rule consists of a nonterminal symbol followed by the special symbol ``::='' and then a list of terminals and/or nonterminals. The rule is terminated by a period. The list of terminals and nonterminals on the right-hand side of the rule can be empty. Rules can occur in any order, except that the left-hand side of the first rule is assumed to be the start symbol for the grammar (unless specified otherwise using the %start directive described below.) A typical sequence of grammar rules might look something like this: + + expr ::= expr PLUS expr. + expr ::= expr TIMES expr. + expr ::= LPAREN expr RPAREN. + expr ::= VALUE. + +There is one non-terminal in this example, ``expr'', and five terminal symbols or tokens: ``PLUS'', ``TIMES'', ``LPAREN'', ``RPAREN'' and ``VALUE''. + +Like yacc and bison, Lemon allows the grammar to specify a block of C code that will be executed whenever a grammar rule is reduced by the parser. In Lemon, this action is specified by putting the C code (contained within curly braces {...}) immediately after the period that closes the rule. For example: + + expr ::= expr PLUS expr. { printf("Doing an addition...\n"); } + +In order to be useful, grammar actions must normally be linked to their associated grammar rules. In yacc and bison, this is accomplished by embedding a ``$$'' in the action to stand for the value of the left-hand side of the rule and symbols ``$1'', ``$2'', and so forth to stand for the value of the terminal or nonterminal at position 1, 2 and so forth on the right-hand side of the rule. This idea is very powerful, but it is also very error-prone. The single most common source of errors in a yacc or bison grammar is to miscount the number of symbols on the right-hand side of a grammar rule and say ``$7'' when you really mean ``$8''. + +Lemon avoids the need to count grammar symbols by assigning symbolic names to each symbol in a grammar rule and then using those symbolic names in the action. In yacc or bison, one would write this: + + expr -> expr PLUS expr { $$ = $1 + $3; }; + +But in Lemon, the same rule becomes the following: + + expr(A) ::= expr(B) PLUS expr(C). { A = B+C; } + +In the Lemon rule, any symbol in parentheses after a grammar rule symbol becomes a place holder for that symbol in the grammar rule. This place holder can then be used in the associated C action to stand for the value of that symbol. + +The Lemon notation for linking a grammar rule with its reduce action is superior to yacc/bison on several counts. First, as mentioned above, the Lemon method avoids the need to count grammar symbols. Secondly, if a terminal or nonterminal in a Lemon grammar rule includes a linking symbol in parentheses but that linking symbol is not actually used in the reduce action, then an error message is generated. For example, the rule + + expr(A) ::= expr(B) PLUS expr(C). { A = B; } + +will generate an error because the linking symbol ``C'' is used in the grammar rule but not in the reduce action. + +The Lemon notation for linking grammar rules to reduce actions also facilitates the use of destructors for reclaiming memory allocated by the values of terminals and nonterminals on the right-hand side of a rule. +Precedence Rules + +Lemon resolves parsing ambiguities in exactly the same way as yacc and bison. A shift-reduce conflict is resolved in favor of the shift, and a reduce-reduce conflict is resolved by reducing whichever rule comes first in the grammar file. + +Just like in yacc and bison, Lemon allows a measure of control over the resolution of paring conflicts using precedence rules. A precedence value can be assigned to any terminal symbol using the %left, %right or %nonassoc directives. Terminal symbols mentioned in earlier directives have a lower precedence that terminal symbols mentioned in later directives. For example: + + %left AND. + %left OR. + %nonassoc EQ NE GT GE LT LE. + %left PLUS MINUS. + %left TIMES DIVIDE MOD. + %right EXP NOT. + +In the preceding sequence of directives, the AND operator is defined to have the lowest precedence. The OR operator is one precedence level higher. And so forth. Hence, the grammar would attempt to group the ambiguous expression + + a AND b OR c + +like this + + a AND (b OR c). + +The associativity (left, right or nonassoc) is used to determine the grouping when the precedence is the same. AND is left-associative in our example, so + + a AND b AND c + +is parsed like this + + (a AND b) AND c. + +The EXP operator is right-associative, though, so + + a EXP b EXP c + +is parsed like this + + a EXP (b EXP c). + +The nonassoc precedence is used for non-associative operators. So + + a EQ b EQ c + +is an error. + +The precedence of non-terminals is transferred to rules as follows: The precedence of a grammar rule is equal to the precedence of the left-most terminal symbol in the rule for which a precedence is defined. This is normally what you want, but in those cases where you want to precedence of a grammar rule to be something different, you can specify an alternative precedence symbol by putting the symbol in square braces after the period at the end of the rule and before any C-code. For example: + + expr = MINUS expr. [NOT] + +This rule has a precedence equal to that of the NOT symbol, not the MINUS symbol as would have been the case by default. + +With the knowledge of how precedence is assigned to terminal symbols and individual grammar rules, we can now explain precisely how parsing conflicts are resolved in Lemon. Shift-reduce conflicts are resolved as follows: + + * If either the token to be shifted or the rule to be reduced lacks precedence information, then resolve in favor of the shift, but report a parsing conflict. + * If the precedence of the token to be shifted is greater than the precedence of the rule to reduce, then resolve in favor of the shift. No parsing conflict is reported. + * If the precedence of the token it be shifted is less than the precedence of the rule to reduce, then resolve in favor of the reduce action. No parsing conflict is reported. + * If the precedences are the same and the shift token is right-associative, then resolve in favor of the shift. No parsing conflict is reported. + * If the precedences are the same the the shift token is left-associative, then resolve in favor of the reduce. No parsing conflict is reported. + * Otherwise, resolve the conflict by doing the shift and report the parsing conflict. + +Reduce-reduce conflicts are resolved this way: + + * If either reduce rule lacks precedence information, then resolve in favor of the rule that appears first in the grammar and report a parsing conflict. + * If both rules have precedence and the precedence is different then resolve the dispute in favor of the rule with the highest precedence and do not report a conflict. + * Otherwise, resolve the conflict by reducing by the rule that appears first in the grammar and report a parsing conflict. + +Special Directives + +The input grammar to Lemon consists of grammar rules and special directives. We've described all the grammar rules, so now we'll talk about the special directives. + +Directives in lemon can occur in any order. You can put them before the grammar rules, or after the grammar rules, or in the mist of the grammar rules. It doesn't matter. The relative order of directives used to assign precedence to terminals is important, but other than that, the order of directives in Lemon is arbitrary. + +Lemon supports the following special directives: + + * %destructor + * %extra_argument + * %include + * %left + * %name + * %nonassoc + * %parse_accept + * %parse_failure + * %right + * %stack_overflow + * %stack_size + * %start_symbol + * %syntax_error + * %token_destructor + * %token_prefix + * %token_type + * %type + +Each of these directives will be described separately in the following sections: + +The %destructor directive + +The %destructor directive is used to specify a destructor for a non-terminal symbol. (See also the %token_destructor directive which is used to specify a destructor for terminal symbols.) + +A non-terminal's destructor is called to dispose of the non-terminal's value whenever the non-terminal is popped from the stack. This includes all of the following circumstances: + + * When a rule reduces and the value of a non-terminal on the right-hand side is not linked to C code. + * When the stack is popped during error processing. + * When the ParseFree() function runs. + +The destructor can do whatever it wants with the value of the non-terminal, but its design is to deallocate memory or other resources held by that non-terminal. + +Consider an example: + + %type nt {void*} + %destructor nt { free($$); } + nt(A) ::= ID NUM. { A = malloc( 100 ); } + +This example is a bit contrived but it serves to illustrate how destructors work. The example shows a non-terminal named ``nt'' that holds values of type ``void*''. When the rule for an ``nt'' reduces, it sets the value of the non-terminal to space obtained from malloc(). Later, when the nt non-terminal is popped from the stack, the destructor will fire and call free() on this malloced space, thus avoiding a memory leak. (Note that the symbol ``$$'' in the destructor code is replaced by the value of the non-terminal.) + +It is important to note that the value of a non-terminal is passed to the destructor whenever the non-terminal is removed from the stack, unless the non-terminal is used in a C-code action. If the non-terminal is used by C-code, then it is assumed that the C-code will take care of destroying it if it should really be destroyed. More commonly, the value is used to build some larger structure and we don't want to destroy it, which is why the destructor is not called in this circumstance. + +By appropriate use of destructors, it is possible to build a parser using Lemon that can be used within a long-running program, such as a GUI, that will not leak memory or other resources. To do the same using yacc or bison is much more difficult. +The %extra_argument directive +The %extra_argument directive instructs Lemon to add a 4th parameter to the parameter list of the Parse() function it generates. Lemon doesn't do anything itself with this extra argument, but it does make the argument available to C-code action routines, destructors, and so forth. For example, if the grammar file contains: + + %extra_argument { MyStruct *pAbc } + +Then the Parse() function generated will have an 4th parameter of type ``MyStruct*'' and all action routines will have access to a variable named ``pAbc'' that is the value of the 4th parameter in the most recent call to Parse(). +The %include directive + +The %include directive specifies C code that is included at the top of the generated parser. You can include any text you want -- the Lemon parser generator copies to blindly. If you have multiple %include directives in your grammar file, their values are concatenated before being put at the beginning of the generated parser. + +The %include directive is very handy for getting some extra #include preprocessor statements at the beginning of the generated parser. For example: + + %include {#include } + +This might be needed, for example, if some of the C actions in the grammar call functions that are prototyed in unistd.h. +The %left directive +The %left directive is used (along with the %right and %nonassoc directives) to declare precedences of terminal symbols. Every terminal symbol whose name appears after a %left directive but before the next period (``.'') is given the same left-associative precedence value. Subsequent %left directives have higher precedence. For example: + + %left AND. + %left OR. + %nonassoc EQ NE GT GE LT LE. + %left PLUS MINUS. + %left TIMES DIVIDE MOD. + %right EXP NOT. + +Note the period that terminates each %left, %right or %nonassoc directive. + +LALR(1) grammars can get into a situation where they require a large amount of stack space if you make heavy use or right-associative operators. For this reason, it is recommended that you use %left rather than %right whenever possible. +The %name directive + +By default, the functions generated by Lemon all begin with the five-character string ``Parse''. You can change this string to something different using the %name directive. For instance: + + %name Abcde + +Putting this directive in the grammar file will cause Lemon to generate functions named + + * AbcdeAlloc(), + * AbcdeFree(), + * AbcdeTrace(), and + * Abcde(). + +The %name directive allows you to generator two or more different parsers and link them all into the same executable. + +The %nonassoc directive + +This directive is used to assign non-associative precedence to one or more terminal symbols. See the section on precedence rules or on the %left directive for additional information. +The %parse_accept directive + +The %parse_accept directive specifies a block of C code that is executed whenever the parser accepts its input string. To ``accept'' an input string means that the parser was able to process all tokens without error. + +For example: + + %parse_accept { + printf("parsing complete!\n"); + } + +The %parse_failure directive + +The %parse_failure directive specifies a block of C code that is executed whenever the parser fails complete. This code is not executed until the parser has tried and failed to resolve an input error using is usual error recovery strategy. The routine is only invoked when parsing is unable to continue. + + %parse_failure { + fprintf(stderr,"Giving up. Parser is hopelessly lost...\n"); + } + +The %right directive + +This directive is used to assign right-associative precedence to one or more terminal symbols. See the section on precedence rules or on the %left directive for additional information. +The %stack_overflow directive + +The %stack_overflow directive specifies a block of C code that is executed if the parser's internal stack ever overflows. Typically this just prints an error message. After a stack overflow, the parser will be unable to continue and must be reset. + + %stack_overflow { + fprintf(stderr,"Giving up. Parser stack overflow\n"); + } + +You can help prevent parser stack overflows by avoiding the use of right recursion and right-precedence operators in your grammar. Use left recursion and and left-precedence operators instead, to encourage rules to reduce sooner and keep the stack size down. For example, do rules like this: + + list ::= list element. // left-recursion. Good! + list ::= . + +Not like this: + + list ::= element list. // right-recursion. Bad! + list ::= . + +The %stack_size directive + +If stack overflow is a problem and you can't resolve the trouble by using left-recursion, then you might want to increase the size of the parser's stack using this directive. Put an positive integer after the %stack_size directive and Lemon will generate a parse with a stack of the requested size. The default value is 100. + + %stack_size 2000 + +The %start_symbol directive + +By default, the start-symbol for the grammar that Lemon generates is the first non-terminal that appears in the grammar file. But you can choose a different start-symbol using the %start_symbol directive. + + %start_symbol prog + +The %token_destructor directive + +The %destructor directive assigns a destructor to a non-terminal symbol. (See the description of the %destructor directive above.) This directive does the same thing for all terminal symbols. + +Unlike non-terminal symbols which may each have a different data type for their values, terminals all use the same data type (defined by the %token_type directive) and so they use a common destructor. Other than that, the token destructor works just like the non-terminal destructors. +The %token_prefix directive + +Lemon generates #defines that assign small integer constants to each terminal symbol in the grammar. If desired, Lemon will add a prefix specified by this directive to each of the #defines it generates. So if the default output of Lemon looked like this: + + #define AND 1 + #define MINUS 2 + #define OR 3 + #define PLUS 4 + +You can insert a statement into the grammar like this: + + %token_prefix TOKEN_ + +to cause Lemon to produce these symbols instead: + + #define TOKEN_AND 1 + #define TOKEN_MINUS 2 + #define TOKEN_OR 3 + #define TOKEN_PLUS 4 + +The %token_type and %type directives + +These directives are used to specify the data types for values on the parser's stack associated with terminal and non-terminal symbols. The values of all terminal symbols must be of the same type. This turns out to be the same data type as the 3rd parameter to the Parse() function generated by Lemon. Typically, you will make the value of a terminal symbol by a pointer to some kind of token structure. Like this: + + %token_type {Token*} + +If the data type of terminals is not specified, the default value is ``int''. + +Non-terminal symbols can each have their own data types. Typically the data type of a non-terminal is a pointer to the root of a parse-tree structure that contains all information about that non-terminal. For example: + + %type expr {Expr*} + +Each entry on the parser's stack is actually a union containing instances of all data types for every non-terminal and terminal symbol. Lemon will automatically use the correct element of this union depending on what the corresponding non-terminal or terminal symbol is. But the grammar designer should keep in mind that the size of the union will be the size of its largest element. So if you have a single non-terminal whose data type requires 1K of storage, then your 100 entry parser stack will require 100K of heap space. If you are willing and able to pay that price, fine. You just need to know. +Error Processing + +After extensive experimentation over several years, it has been discovered that the error recovery strategy used by yacc is about as good as it gets. And so that is what Lemon uses. + +When a Lemon-generated parser encounters a syntax error, it first invokes the code specified by the %syntax_error directive, if any. It then enters its error recovery strategy. The error recovery strategy is to begin popping the parsers stack until it enters a state where it is permitted to shift a special non-terminal symbol named ``error''. It then shifts this non-terminal and continues parsing. But the %syntax_error routine will not be called again until at least three new tokens have been successfully shifted. + +If the parser pops its stack until the stack is empty, and it still is unable to shift the error symbol, then the %parse_failed routine is invoked and the parser resets itself to its start state, ready to begin parsing a new file. This is what will happen at the very first syntax error, of course, if there are no instances of the ``error'' non-terminal in your grammar. + diff --git a/sysutils/pm/lemon/lempar.c b/sysutils/pm/lemon/lempar.c new file mode 100644 index 0000000..774b875 --- /dev/null +++ b/sysutils/pm/lemon/lempar.c @@ -0,0 +1,842 @@ +/* Driver template for the LEMON parser generator. +** The author disclaims copyright to this source code. +*/ +/* First off, code is included that follows the "include" declaration +** in the input grammar file. */ +#include +%% +/* Next is all token values, in a form suitable for use by makeheaders. +** This section will be null unless lemon is run with the -m switch. +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ +%% +/* Make sure the INTERFACE macro is defined. +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** YYCODETYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 terminals +** and nonterminals. "int" is used otherwise. +** YYNOCODE is a number of type YYCODETYPE which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** YYACTIONTYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 rules and +** states combined. "int" is used otherwise. +** ParseTOKENTYPE is the data type used for minor tokens given +** directly to the parser from the tokenizer. +** YYMINORTYPE is the data type used for all minor tokens. +** This is typically a union of many types, one of +** which is ParseTOKENTYPE. The entry in the union +** for base tokens is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** ParseARG_SDECL A static variable declaration for the %extra_argument +** ParseARG_PDECL A parameter declaration for the %extra_argument +** ParseARG_STORE Code to store %extra_argument into yypParser +** ParseARG_FETCH Code to extract %extra_argument from yypParser +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ +%% +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) + +/* The yyzerominor constant is used to initialize instances of +** YYMINORTYPE objects to zero. */ +static const YYMINORTYPE yyzerominor = { 0 }; + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** +** N == YYNSTATE+YYNRULE A syntax error has occurred. +** +** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as +** +** yy_action[ yy_shift_ofst[S] + X ] +** +** If the index value yy_shift_ofst[S]+X is out of range or if the value +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table +** and that yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of +** YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +*/ +%% +#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0])) + +/* The next table maps tokens into fallback tokens. If a construct +** like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { +%% +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +*/ +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + int yyidx; /* Index of top element in stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyidxMax; /* Maximum value of yyidx */ +#endif + int yyerrcnt; /* Shifts left before out of the error */ + ParseARG_SDECL /* A place to hold %extra_argument */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +#include +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { +%% +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { +%% +}; +#endif /* NDEBUG */ + + +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. +*/ +static void yyGrowStack(yyParser *p){ + int newSize; + yyStackEntry *pNew; + + newSize = p->yystksz*2 + 100; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + if( pNew ){ + p->yystack = pNew; + p->yystksz = newSize; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", + yyTracePrompt, p->yystksz); + } +#endif + } +} +#endif + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to Parse and ParseFree. +*/ +void *ParseAlloc(void *(*mallocProc)(size_t)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + if( pParser ){ + pParser->yyidx = -1; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyidxMax = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yystack = NULL; + pParser->yystksz = 0; + yyGrowStack(pParser); +#endif + } + return pParser; +} + +/* The following function deletes the value associated with a +** symbol. The symbol can be either a terminal or nonterminal. +** "yymajor" is the symbol code, and "yypminor" is a pointer to +** the value. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + ParseARG_FETCH; + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ +%% + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +** +** Return the major token number for the symbol popped. +*/ +static int yy_pop_parser_stack(yyParser *pParser){ + YYCODETYPE yymajor; + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; + + if( pParser->yyidx<0 ) return 0; +#ifndef NDEBUG + if( yyTraceFILE && pParser->yyidx>=0 ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yymajor = yytos->major; + yy_destructor(pParser, yymajor, &yytos->minor); + pParser->yyidx--; + return yymajor; +} + +/* +** Deallocate and destroy a parser. Destructors are all called for +** all stack elements before shutting the parser down. +** +** Inputs: +**
    +**
  • A pointer to the parser. This should be a pointer +** obtained from ParseAlloc. +**
  • A pointer to a function used to reclaim memory obtained +** from malloc. +**
+*/ +void ParseFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + yyParser *pParser = (yyParser*)p; + if( pParser==0 ) return; + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + free(pParser->yystack); +#endif + (*freeProc)((void*)pParser); +} + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int ParseStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyidxMax; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_shift_action( + yyParser *pParser, /* The parser */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->yystack[pParser->yyidx].stateno; + + if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ + return yy_default[stateno]; + } + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + return yy_find_shift_action(pParser, iFallback); + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( j>=0 && j %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; + } +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_reduce_action( + int stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_MAX ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_MAX ); +#endif + i = yy_reduce_ofst[stateno]; + assert( i!=YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyyidx--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +%% + ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yyidx++; +#ifdef YYTRACKMAXSTACKDEPTH + if( yypParser->yyidx>yypParser->yyidxMax ){ + yypParser->yyidxMax = yypParser->yyidx; + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yyidx>=YYSTACKDEPTH ){ + yyStackOverflow(yypParser, yypMinor); + return; + } +#else + if( yypParser->yyidx>=yypParser->yystksz ){ + yyGrowStack(yypParser); + if( yypParser->yyidx>=yypParser->yystksz ){ + yyStackOverflow(yypParser, yypMinor); + return; + } + } +#endif + yytos = &yypParser->yystack[yypParser->yyidx]; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; + yytos->minor = *yypMinor; +#ifndef NDEBUG + if( yyTraceFILE && yypParser->yyidx>0 ){ + int i; + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + } +#endif +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { +%% +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + ParseARG_FETCH; + yymsp = &yypParser->yystack[yypParser->yyidx]; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno>=0 + && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, + yyRuleName[yyruleno]); + } +#endif /* NDEBUG */ + + /* Silence complaints from purify about yygotominor being uninitialized + ** in some cases when it is copied into the stack after the following + ** switch. yygotominor is uninitialized when a rule reduces that does + ** not set the value of its left-hand side nonterminal. Leaving the + ** value of the nonterminal uninitialized is utterly harmless as long + ** as the value is never used. So really the only thing this code + ** accomplishes is to quieten purify. + ** + ** 2007-01-16: The wireshark project (www.wireshark.org) reports that + ** without this code, their parser segfaults. I'm not sure what there + ** parser is doing to make this happen. This is the second bug report + ** from wireshark this week. Clearly they are stressing Lemon in ways + ** that it has not been previously stressed... (SQLite ticket #2172) + */ + /*memset(&yygotominor, 0, sizeof(yygotominor));*/ + yygotominor = yyzerominor; + + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ +%% + }; + yygoto = yyRuleInfo[yyruleno].lhs; + yysize = yyRuleInfo[yyruleno].nrhs; + yypParser->yyidx -= yysize; + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); + if( yyact < YYNSTATE ){ +#ifdef NDEBUG + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if( yysize ){ + yypParser->yyidx++; + yymsp -= yysize-1; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yymsp->minor = yygotominor; + }else +#endif + { + yy_shift(yypParser,yyact,yygoto,&yygotominor); + } + }else{ + assert( yyact == YYNSTATE + YYNRULE + 1 ); + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + ParseARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ +%% + ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + YYMINORTYPE yyminor /* The minor type of the error token */ +){ + ParseARG_FETCH; +#define TOKEN (yyminor.yy0) +%% + ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + ParseARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +%% + ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "ParseAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +void Parse( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + ParseTOKENTYPE yyminor /* The value for the token */ + ParseARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + int yyact; /* The parser action. */ + int yyendofinput; /* True if we are at the end of input */ +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser; /* The parser */ + + /* (re)initialize the parser, if necessary */ + yypParser = (yyParser*)yyp; + if( yypParser->yyidx<0 ){ +#if YYSTACKDEPTH<=0 + if( yypParser->yystksz <=0 ){ + /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ + yyminorunion = yyzerominor; + yyStackOverflow(yypParser, &yyminorunion); + return; + } +#endif + yypParser->yyidx = 0; + yypParser->yyerrcnt = -1; + yypParser->yystack[0].stateno = 0; + yypParser->yystack[0].major = 0; + } + yyminorunion.yy0 = yyminor; + yyendofinput = (yymajor==0); + ParseARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + if( yyactyyerrcnt--; + yymajor = YYNOCODE; + }else if( yyact < YYNSTATE + YYNRULE ){ + yy_reduce(yypParser,yyact-YYNSTATE); + }else{ + assert( yyact == YY_ERROR_ACTION ); +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yymx = yypParser->yystack[yypParser->yyidx].major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + }else{ + while( + yypParser->yyidx >= 0 && + yymx != YYERRORSYMBOL && + (yyact = yy_find_reduce_action( + yypParser->yystack[yypParser->yyidx].stateno, + YYERRORSYMBOL)) >= YYNSTATE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yyidx < 0 || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + YYMINORTYPE u2; + u2.YYERRSYMDT = 0; + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); + } + yymajor = YYNOCODE; +#endif + } + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + return; +} diff --git a/sysutils/pm/pm.c b/sysutils/pm/pm.c new file mode 100644 index 0000000..fd4572d --- /dev/null +++ b/sysutils/pm/pm.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utstring.h" +#include "utarray.h" +#include "job.h" + +#define DEFAULT_PM_CONFIG "/etc/pm.conf" +#define SHORT_DELAY 10 + +char proctitle[16] = "pm"; +sigjmp_buf jmp; + +struct { + char *file; + int verbose; + int foreground; + int alarm_pending; + int test_only; + UT_array *jobs; +} cfg = { + .verbose = 0, + .foreground = 0, + .alarm_pending = 0, +}; + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-F] [-c cfg] [-t]\n", prog); + fprintf(stderr, " -v verbose\n"); + fprintf(stderr, " -F foreground\n"); + fprintf(stderr, " -c specify configuration file\n"); + fprintf(stderr, " -t test only; parse config file only (implies -F)\n"); + exit(-1); +} + +void sighandler(int signo) { + siglongjmp(jmp,signo); +} + +/* fork a process that signals us if the config file changes */ +pid_t dep_monitor(char *file) { + size_t eblen = sizeof(struct inotify_event)+PATH_MAX; + char *eb; + int rc,fd,wd; + pid_t dm_pid = fork(); + if (dm_pid > 0) return dm_pid; + if ((dm_pid == (pid_t)-1) || + ( (fd=inotify_init()) == -1) || + ( (wd=inotify_add_watch(fd,file,IN_MODIFY)) == -1)) { + syslog(LOG_ERR,"error: %s\n", strerror(errno)); + exit(-1); + } + + /* request HUP if parent exits, unblock, action terminate */ + signal(SIGHUP, SIG_DFL); + prctl(PR_SET_PDEATHSIG, SIGHUP); + sigset_t hup; sigemptyset(&hup); sigaddset(&hup,SIGHUP); + sigprocmask(SIG_UNBLOCK,&hup,NULL); + + eb = malloc(eblen); + rc = read(fd,eb,eblen); + kill(getppid(), SIGHUP); + free(eb); + exit(0); +} + +int rescan_config(void) { + syslog(LOG_INFO,"rescanning job configuration"); + UT_array *jobs; utarray_new(jobs, &job_mm); + UT_string *em; utstring_new(em); + if (parse_jobs(jobs, em, cfg.file, cfg.verbose) == -1) { + syslog(LOG_ERR,"parse failed: %s\n", utstring_body(em)); + syslog(LOG_ERR,"retaining previous configuration\n"); + goto done; + } + /* compare the new jobs to the existing jobs */ + job_t *job=NULL, *pjob; + while( (job = (job_t*)utarray_next(jobs,job))) { + pjob = get_job_by_name(cfg.jobs, job->name); + if (!pjob) continue; // new job definition; startup forthcoming + if (job_cmp(job,pjob) == 0) { // new job identical to old + job->pid = pjob->pid; + job->start_ts = pjob->start_ts; + job->respawn = pjob->respawn; + } else { + term_job(pjob); // job definition changed; job restart required + } + utarray_erase(cfg.jobs, utarray_eltidx(cfg.jobs,pjob), 1); + } + /* any jobs left in cfg.jobs are no longer in the new configuration */ + pjob=NULL; + while ( (pjob=(job_t*)utarray_next(cfg.jobs,pjob))) term_job(pjob); + /* set the new job definition. these'll be started in do_jobs, if needed, */ + utarray_clear(cfg.jobs); + utarray_concat(cfg.jobs,jobs); + + done: + utarray_free(jobs); + utstring_free(em); +} + +int main (int argc, char *argv[]) { + int n, opt, es, elapsed, defer_restart; + job_t *job; + pid_t pid, dm_pid=0; + + UT_string *em, *sm; + utstring_new(em); + utstring_new(sm); + + while ( (opt = getopt(argc, argv, "v+Fc:s:t")) != -1) { + switch (opt) { + case 'v': cfg.verbose++; break; + case 'F': cfg.foreground=1; break; + case 'c': cfg.file=strdup(optarg); break; + case 't': cfg.test_only=1; cfg.foreground=1; break; + default: usage(argv[0]); break; + } + } + openlog("pm", LOG_PID | (cfg.foreground ? LOG_PERROR : 0), LOG_LOCAL0); + if (!cfg.file) cfg.file = strdup(DEFAULT_PM_CONFIG); + utarray_new(cfg.jobs, &job_mm); + if (parse_jobs(cfg.jobs, em, cfg.file, cfg.verbose) == -1) { + syslog(LOG_ERR,"parse failed: %s\n", utstring_body(em)); + goto done; + } + if (cfg.test_only) goto done; + syslog(LOG_INFO,"pm: managing %d jobs\n", (int)utarray_len(cfg.jobs)); + snprintf(proctitle,sizeof(proctitle),"pm [%d jobs]", (int)utarray_len(cfg.jobs)); + prctl(PR_SET_NAME,(unsigned long)proctitle,0,0,0); + + if (!cfg.foreground) { /* daemon init */ + if (fork() != 0) exit(0); /* parent exit */ + setsid(); /* new session - no controlling terminal */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + umask(0); + + /* block all signals. we remain fully blocked except in sigsuspend */ + sigset_t all; + sigfillset(&all); + sigprocmask(SIG_SETMASK,&all,NULL); + + /* define a smaller set of signals to block within sigsuspend. */ + sigset_t ss; + sigfillset(&ss); + for(n=0; n < sizeof(sigs)/sizeof(*sigs); n++) sigdelset(&ss, sigs[n]); + + /* establish handlers for signals that we'll unblock in sigsuspend */ + struct sigaction sa; + sa.sa_handler = sighandler; + sa.sa_flags = 0; + sigfillset(&sa.sa_mask); + for(n=0; n < sizeof(sigs)/sizeof(*sigs); n++) sigaction(sigs[n], &sa, NULL); + + /* here is a special line. we'll come back here whenever a signal happens */ + int signo = sigsetjmp(jmp,1); + + switch(signo) { + case 0: /* not a signal yet, first time setup */ + do_jobs(cfg.jobs); + dm_pid = dep_monitor(cfg.file); + break; + case SIGHUP: + rescan_config(); + do_jobs(cfg.jobs); + break; + case SIGCHLD: + /* loop over children that have exited */ + defer_restart=0; + while ( (pid = waitpid(-1, &es, WNOHANG)) > 0) { + if (pid == dm_pid) { dm_pid = dep_monitor(cfg.file); continue; } + job = get_job_by_pid(cfg.jobs, pid); + if (!job) { + /* maybe exited, then while sigchld pending, collected in reconfig */ + syslog(LOG_ERR,"sigchld for unknown pid %d", (int)pid); + goto done; /* restart for sanity purposes */ + break; + } + job->pid = 0; + elapsed = time(NULL) - job->start_ts; + if (elapsed < SHORT_DELAY) defer_restart=1; + utstring_clear(sm); + utstring_printf(sm,"job %s %d exited after %d sec: ",job->name, (int)pid, elapsed); + if (WIFSIGNALED(es)) utstring_printf(sm, "signal %d", (int)WTERMSIG(es)); + else if (WIFEXITED(es)) { + int ex = WEXITSTATUS(es); + utstring_printf(sm,"exit status %d", ex); + if (job->once || (ex == PM_NO_RESTART)) { + job->respawn=0; + utstring_printf(sm," (will not be restarted)"); + } + } + syslog(LOG_INFO,"%s",utstring_body(sm)); + } + if (defer_restart) { + if (!cfg.alarm_pending) { + syslog(LOG_INFO,"job restarting too fast, delaying restart\n"); + cfg.alarm_pending++; + alarm(SHORT_DELAY); + } + } else { + do_jobs(cfg.jobs); + } + break; + case SIGALRM: + assert(cfg.alarm_pending == 1); + cfg.alarm_pending=0; + do_jobs(cfg.jobs); + break; + default: + syslog(LOG_INFO,"pm: exiting on signal %d\n", signo); + goto done; + break; + } + + /* wait for signals */ + sigsuspend(&ss); + + /* the only way to get past this point + * is from the "goto done" above, because + * sigsuspend waits for signals, and when + * one arrives we longjmp back to sigsetjmp! */ + + done: + term_jobs(cfg.jobs); + free(cfg.file); + utarray_free(cfg.jobs); + utstring_free(em); + utstring_free(sm); + return 0; +} diff --git a/sysutils/pm/test/bad.txt b/sysutils/pm/test/bad.txt new file mode 100644 index 0000000..13d2d89 --- /dev/null +++ b/sysutils/pm/test/bad.txt @@ -0,0 +1,8 @@ +job { + name echoer + cmd /bin/echo out + out /tmp/e.out + err /tmp/e.err + dir /tmp +} + diff --git a/sysutils/pm/test/dm.conf b/sysutils/pm/test/dm.conf new file mode 100644 index 0000000..96b2715 --- /dev/null +++ b/sysutils/pm/test/dm.conf @@ -0,0 +1,16 @@ +job { + name dm + cmd /usr/local/bin/dm -c test/dm.conf +} + +# modify me to induce dm to signal pm (causing pm to rescan) +job { + name guinea_pig + cmd /bin/bash -c "echo hello; sleep 10; exit 33" +} + +job { + name other + cmd /bin/bash -c "logger hello from other; sleep 10" +} +# etc diff --git a/sysutils/pm/test/dup.txt b/sysutils/pm/test/dup.txt new file mode 100644 index 0000000..5fce5f4 --- /dev/null +++ b/sysutils/pm/test/dup.txt @@ -0,0 +1,8 @@ +job { + name job1 + cmd /usr/local/bin/job + dir /var/log/ + dir /var/log/ + out out.txt + err err.txt +} diff --git a/sysutils/pm/test/env.txt b/sysutils/pm/test/env.txt new file mode 100644 index 0000000..ab3782d --- /dev/null +++ b/sysutils/pm/test/env.txt @@ -0,0 +1,7 @@ +job { + name test + env BLAH=FOO + cmd /bin/bash -c "echo $BLAH" + out /tmp/w.out + err /tmp/w.err +} diff --git a/sysutils/pm/test/job.txt b/sysutils/pm/test/job.txt new file mode 100644 index 0000000..102cdb0 --- /dev/null +++ b/sysutils/pm/test/job.txt @@ -0,0 +1,7 @@ +job { + name job1 + cmd /usr/local/bin/job + dir /var/log/ + out out.txt + err err.txt +} diff --git a/sysutils/pm/test/job2.txt b/sysutils/pm/test/job2.txt new file mode 100644 index 0000000..a05e521 --- /dev/null +++ b/sysutils/pm/test/job2.txt @@ -0,0 +1,10 @@ +job { + name job2 + cmd /usr/local/bin/job -id 2 -exec "ls -l" + # comment + dir /var/log/ + out out.txt + err err.txt +} + + diff --git a/sysutils/pm/test/jobs.txt b/sysutils/pm/test/jobs.txt new file mode 100644 index 0000000..0b48508 --- /dev/null +++ b/sysutils/pm/test/jobs.txt @@ -0,0 +1,19 @@ +job { + name job1 + cmd /bin/date + dir /tmp + out job1.out + err job1.err + order 1 +} + +job { + name job2 + cmd /usr/bin/find . -type f -exec ls -l {} ; + # comment + dir /tmp + out job2.out + err job2.err +} + + diff --git a/sysutils/pm/test/jobs_nonl.txt b/sysutils/pm/test/jobs_nonl.txt new file mode 100644 index 0000000..a93d46f --- /dev/null +++ b/sysutils/pm/test/jobs_nonl.txt @@ -0,0 +1,26 @@ +job +{ + name job2 + cmd /usr/bin/find . -type f -exec ls -l {} ; + dir /tmp + out job2.out + err job2.err +} + +job +{ + name job2 + cmd /usr/bin/find . -type f -exec ls -l {} ; + dir /tmp + out job2.out + err job2.err +} + +job +{ + name job2 + cmd /usr/bin/find . -type f -exec ls -l {} ; + dir /tmp + out job2.out + err job2.err +} diff --git a/sysutils/pm/test/norespawn.txt b/sysutils/pm/test/norespawn.txt new file mode 100644 index 0000000..079b18a --- /dev/null +++ b/sysutils/pm/test/norespawn.txt @@ -0,0 +1,4 @@ +job { + name no-respawn + cmd /bin/bash -c "sleep 10; exit 33;" +} diff --git a/sysutils/pm/test/sleep.txt b/sysutils/pm/test/sleep.txt new file mode 100644 index 0000000..3a9bce7 --- /dev/null +++ b/sysutils/pm/test/sleep.txt @@ -0,0 +1,31 @@ +job { + name sleepy2 + cmd /bin/sleep 20 + dir /tmp + out job1.out + err job1.err + order -1 + disable +} + +job { + name sleepy4 + #cmd /bin/bash -c "/bin/sleep 20; exit 33" + cmd /bin/bash -c "/bin/sleep 20" + dir /tmp + out job1.out + err job1.err + order 0 + #wait + #once +} + +job { + name sleepy1 + cmd /bin/sleep 20 + dir /tmp + out job1.out + err job1.err + order 1 +} + diff --git a/sysutils/pm/test/usr.txt b/sysutils/pm/test/usr.txt new file mode 100644 index 0000000..22c109c --- /dev/null +++ b/sysutils/pm/test/usr.txt @@ -0,0 +1,9 @@ +job { + name job1 + cmd /usr/local/bin/job + #tmp /var/log/ + dir /tmp + out out.txt + err err.txt + user root +} diff --git a/sysutils/pm/tok.c b/sysutils/pm/tok.c new file mode 100644 index 0000000..26e11c6 --- /dev/null +++ b/sysutils/pm/tok.c @@ -0,0 +1,91 @@ +#include +#include "cfg.h" + +static struct { + char *str; + size_t len; + int id; +} kw[] = +{ + {"job", 3, TOK_JOB}, + {"name", 4, TOK_NAME}, + {"user", 4, TOK_USER}, + {"cmd", 3, TOK_CMD}, + {"env", 3, TOK_ENV}, + {"dir", 3, TOK_DIR}, + {"out", 3, TOK_OUT}, + {"err", 3, TOK_ERR}, + {"order", 5, TOK_ORDER}, + {"disable", 7, TOK_DISABLED}, + {"wait", 4, TOK_WAIT}, + {"once", 4, TOK_ONCE}, + {"{", 1, TOK_LCURLY}, + {"}", 1, TOK_RCURLY}, +}; +static const int ws[256] = { ['\r']=1, ['\n']=1, ['\t']=1, [' ']=1 }; + +int get_tok(char *c_orig, char **c, size_t *bsz, size_t *toksz, int *line) { + char *e; + int leading_nl=0; + + again: + /* skip leading whitespace */ + while(*bsz && ws[(int)**c]) { + if (**c=='\n') { + leading_nl=1; + (*line)++; + } + (*bsz)--; (*c)++; + } + if (*bsz == 0) return 0; // end of input + + /* disregard comments til end of line */ + if (**c=='#') { + while (*bsz) { + (*c)++; (*bsz)--; + if (**c == '\n') goto again; + } + return 0; /* eob while looking for trailing newline */ + } + + /* identity literal keywords */ + int i; + for(i=0; i < sizeof(kw)/sizeof(*kw); i++) { + if (*bsz < kw[i].len) continue; + if (memcmp(*c,kw[i].str,kw[i].len) ) continue; + /* keywords except { must be preceded by start-of-buf or newline */ + if (kw[i].id != TOK_LCURLY) { + for(e=(*c)-1; e > c_orig; e--) { + if (*e == '\n') break; + if (ws[(int)*e]) continue; + /* has non-newline chars preceding, so do not consider as a keyword */ + else goto quoted; + } + } + /* require keywords to end with space or eob */ + e = (*bsz > kw[i].len) ? (*c + kw[i].len) : " "; + if (!ws[(int)(*e)]) continue; + *toksz = kw[i].len; + return kw[i].id; + } + + quoted: + /* identify quoted string that ends with the closing quote on same line */ + if (**c=='"') { + *toksz=1; + while (*toksz < *bsz) { + e = *c + *toksz; + (*toksz)++; + if (*e == '"') return TOK_QUOTEDSTR; + if (*e == '\n') return -1; + } + return -1; /* eob without terminating quote */ + } + + /* otherwise its a string ending with end-of-buffer or whitespace */ + *toksz=0; + while ((*toksz < *bsz) && (!ws[(int)*(*c+*toksz)])) (*toksz)++; + if ((*toksz) && (!leading_nl)) return TOK_STR; + + return -1; +} diff --git a/sysutils/pm/upstart/README b/sysutils/pm/upstart/README new file mode 100644 index 0000000..36b1526 --- /dev/null +++ b/sysutils/pm/upstart/README @@ -0,0 +1,7 @@ +This directory contains pm.conf, which is an upstart job. It gets +installed in /etc/init/pm.conf. It's purpose is to start pm itself. + +Note: despite the name pm.conf this is a not a pm (process manager) +configuration file. The latter gets installed in /etc/pm.conf and +contains the jobs being managed within pm. + diff --git a/sysutils/pm/upstart/pm.conf b/sysutils/pm/upstart/pm.conf new file mode 100644 index 0000000..b50088a --- /dev/null +++ b/sysutils/pm/upstart/pm.conf @@ -0,0 +1,20 @@ +# pm.conf +# This is an upstart(8) configuration file. +# upstart is the init replacement on Ubuntu. +# This file gets installed in /etc/init/pm.conf +# +# to start the service manually, "service pm start". +# +# The syntax for this file is documented in init(5). +# The upstart log messages go to /var/log/daemon.log + +description "pm process manager" + +start on runlevel [2345] +stop on runlevel [!2345] + +respawn + +#next line is commented out when using pm -F +#expect fork +exec /usr/local/bin/pm -F -c /etc/pm.conf diff --git a/sysutils/pm/utarray.h b/sysutils/pm/utarray.h new file mode 100644 index 0000000..2f5dcb3 --- /dev/null +++ b/sysutils/pm/utarray.h @@ -0,0 +1,224 @@ +/* +Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + * see http://uthash.sourceforge.net/utarray + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.1 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + const UT_icd *icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + utarray_reserve(a,1); \ + if (j > (a)->i) break; \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) break; \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if (a->icd->copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd->sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd->dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd->init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd->init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr(a,pos), _utarray_eltptr(a,pos+len), \ + ((a->i)-(pos+len))*((a)->icd->sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \ +} while(0) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/sysutils/pm/utstring.h b/sysutils/pm/utstring.h new file mode 100644 index 0000000..277874f --- /dev/null +++ b/sysutils/pm/utstring.h @@ -0,0 +1,137 @@ +/* +Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + * see http://uthash.sourceforge.net/utstring + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.1 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve(s,(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + s->i += l; \ + s->d[s->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve(dst,(src->i)+1); \ + if (src->i) memcpy(&(dst)->d[(dst)->i], src->d, src->i); \ + dst->i += src->i; \ + dst->d[dst->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && (n < (int)(s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +#endif /* UTSTRING_H */ diff --git a/sysutils/qcp/.gitignore b/sysutils/qcp/.gitignore new file mode 100644 index 0000000..aa3c8fc --- /dev/null +++ b/sysutils/qcp/.gitignore @@ -0,0 +1,2 @@ +qcp +qcps diff --git a/sysutils/qcp/Makefile b/sysutils/qcp/Makefile new file mode 100644 index 0000000..bd8f1f9 --- /dev/null +++ b/sysutils/qcp/Makefile @@ -0,0 +1,11 @@ +CFLAGS=-g +EXES = qcp qcps +all: $(EXES) + +.PHONY: clean + +install: $(EXES) + cp $(EXES) /usr/local/bin + +clean: + rm -f *.o $(EXES) diff --git a/sysutils/qcp/qcp.c b/sysutils/qcp/qcp.c new file mode 100644 index 0000000..96319dd --- /dev/null +++ b/sysutils/qcp/qcp.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int verbose=0; +void usage(char *prog) { + fprintf(stderr, "usage: %s -s -p # send one file\n", prog); + fprintf(stderr, " ls | %s -s -p # file names on stdin\n", prog); + exit(-1); +} + +char *server = "127.0.0.1"; +uint16_t port = 2000; +int md; + +char *map(char *file, size_t *len) { + struct stat s; + char *buf; + + if ( (md = open(file, O_RDONLY)) == -1) { + fprintf(stderr,"can't open %s: %s\n", file, strerror(errno)); + exit(-1); + } + if (fstat(md, &s) == -1) { + close(md); + fprintf(stderr,"can't stat %s: %s\n", file, strerror(errno)); + exit(-1); + } + *len = s.st_size; + buf = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, md, 0); + if (buf == MAP_FAILED) { + close(md); + fprintf(stderr, "failed to mmap %s: %s\n", file, strerror(errno)); + exit(-1); + } + /* don't: close(md); */ + return buf; +} + +int send_file(char *filename) { + char *buf, *base; + size_t buflen; + int rc,baselen; + time_t before,after; + + buf = map(filename, &buflen); + if (!buf) return -1; + + /********************************************************** + * create an IPv4/TCP socket, not yet bound to any address + *********************************************************/ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + printf("socket: %s\n", strerror(errno)); + exit(-1); + } + + /********************************************************** + * internet socket address structure, for the remote side + *********************************************************/ + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(server); + sin.sin_port = htons(port); + + if (sin.sin_addr.s_addr == INADDR_NONE) { + printf("invalid remote IP %s\n", server); + exit(-1); + } + + /********************************************************** + * Perform the 3 way handshake, (c)syn, (s)ack/syn, c(ack) + *********************************************************/ + if (connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { + printf("connect: %s\n", strerror(errno)); + exit(-1); + } + + time(&before); + + /* write a length-prefixed filename.*/ + base = basename(filename); + baselen = strlen(base); + if (verbose) fprintf(stderr,"sending %s\n", base); + if (write(fd,&baselen,sizeof(baselen)) != sizeof(baselen)) { + printf("write: %s\n", (rc<0)?strerror(errno):"incomplete"); + exit(-1); + } + + if (write(fd,base,baselen) != baselen) { + printf("write: %s\n", (rc<0)?strerror(errno):"incomplete"); + exit(-1); + } + + /* and write the file content */ + if ( (rc=write(fd,buf,buflen)) != buflen) { + printf("write: %s\n", (rc<0)?strerror(errno):"incomplete"); + exit(-1); + } + close(fd); + time(&after); + int sec = after-before; + if (verbose) fprintf(stderr,"sent in %u sec (%.0f Mbps)\n", sec, + sec ? ((buflen/(1024.0*1024))/sec) :0); + + + munmap(buf,buflen); + close(md); + + if (verbose) printf("sent %s\n",filename); +} + +int main(int argc, char * argv[]) { + int opt; + char *file=NULL, *buf; + size_t len; + char filename[100]; + + while ( (opt = getopt(argc, argv, "v+s:p:h")) != -1) { + switch (opt) { + case 's': server = strdup(optarg); break; + case 'p': port = atoi(optarg); break; + case 'v': verbose++; break; + default: usage(argv[0]); break; + } + } + + if (optind < argc) file=argv[optind++]; + + if (!file) { + while (fgets(filename,sizeof(filename),stdin) != NULL) { + int len = strlen(filename); + if (filename[len-1] == '\n') filename[len-1]='\0'; + send_file(filename); + } + } + else send_file(file); + +} diff --git a/sysutils/qcp/qcps.c b/sysutils/qcp/qcps.c new file mode 100644 index 0000000..2d62c22 --- /dev/null +++ b/sysutils/qcp/qcps.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSZ (200*1024*1024) // 200 mb +char buf[BUFSZ]; +int port = 2000; /* no significance */ +int verbose=0; + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-p ]\n", prog); + exit(-1); +} + + +int main(int argc, char *argv[]) { + + int opt,rc; + int namelen; + char *base; + + while ( (opt = getopt(argc, argv, "v+p:h")) != -1) { + switch (opt) { + case 'p': port = atoi(optarg); break; + case 'v': verbose++; break; + default: usage(argv[0]); break; + } + } + + /********************************************************** + * create an IPv4/TCP socket, not yet bound to any address + *********************************************************/ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + printf("socket: %s\n", strerror(errno)); + exit(-1); + } + + /********************************************************** + * internet socket address structure: our address and port + *********************************************************/ + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + /********************************************************** + * bind socket to address and port we'd like to receive on + *********************************************************/ + if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { + printf("bind: %s\n", strerror(errno)); + exit(-1); + } + + /********************************************************** + * put socket into listening state + *********************************************************/ + if (listen(fd,1) == -1) { + printf("listen: %s\n", strerror(errno)); + exit(-1); + } + + /********************************************************** + * accept a connection, read til it closes, repeat + *********************************************************/ + while (1) { + struct sockaddr_in cin; + socklen_t cin_sz = sizeof(cin); + int fa = accept(fd, (struct sockaddr*)&cin, &cin_sz); + if (fa == -1) { + printf("accept: %s\n", strerror(errno)); + continue; + } + if (sizeof(cin)==cin_sz) { + if (verbose) printf("connection from %s:%d\n", + inet_ntoa(cin.sin_addr), (int)ntohs(cin.sin_port)); + } + /* first read the length prefixed filename */ + if (read(fa,&namelen,sizeof(namelen)) != sizeof(namelen)) { + fprintf(stderr,"failed to read length\n"); + exit(-1); + } + assert(namelen < 200); + if (read(fa,buf,namelen) != namelen) { + fprintf(stderr,"failed to read name\n"); + exit(-1); + } + char *filename = buf; + filename[namelen]='\0'; + base = basename(filename); + int fw = open(base, O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fw == -1) { + fprintf(stderr,"can't open %s: %s\n",filename,strerror(errno)); + exit(-1); + } + if (verbose) fprintf(stderr,"writing %s\n",filename); + do { + rc = read(fa,buf,BUFSZ); + if (rc==-1) printf("read: %s\n", strerror(errno)); + if (rc<=0) close(fw); + else { + //if (verbose) printf("received %d bytes: %.*s\n", rc, rc, buf); + if (write(fw,buf,rc) != rc) { + fprintf(stderr,"error writing to %s: %s\n", filename, strerror(errno)); + exit(-1); + } + } + } while (rc > 0); + close(fa); + } +} diff --git a/sysutils/ramdisk/.gitignore b/sysutils/ramdisk/.gitignore new file mode 100644 index 0000000..fb12a1f --- /dev/null +++ b/sysutils/ramdisk/.gitignore @@ -0,0 +1 @@ +ramdisk diff --git a/sysutils/ramdisk/Makefile b/sysutils/ramdisk/Makefile new file mode 100644 index 0000000..b7744d8 --- /dev/null +++ b/sysutils/ramdisk/Makefile @@ -0,0 +1,11 @@ +OBJS=ramdisk +all: $(OBJS) +CFLAGS=-g + +.PHONY: clean + +clean: + rm -f *.o $(OBJS) + +install: $(OBJS) + cp $(OBJS) /usr/local/bin diff --git a/sysutils/ramdisk/ramdisk.c b/sysutils/ramdisk/ramdisk.c new file mode 100644 index 0000000..1664fb0 --- /dev/null +++ b/sysutils/ramdisk/ramdisk.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utarray.h" + +#define TMPFS_MAGIC 0x01021994 + +/****************************************************************************** + * ramdisk + * a utility with modes to: + * - create a ramdisk, + * - attrition its contents (continually or once) + *****************************************************************************/ + +/* command line configuration parameters */ +int verbose; +enum {MODE_NONE,MODE_QUERY,MODE_CREATE,MODE_UNMOUNT} mode = MODE_NONE; +char *sz="50%"; +char *ramdisk; +UT_array *dirs; + +void usage(char *prog) { + fprintf(stderr, "usage:\n\n"); + fprintf(stderr, "Create ramdisk, unless it already exists:\n"); + fprintf(stderr, " %%%s -c [-s 10g] [-d dir [-d dir]] /path/to/ramdisk\n", prog); + fprintf(stderr, " size is bytes, or suffixed with k|m|g|%% [def: 50%%]\n"); + fprintf(stderr, " [-d dir] are dirs in ramdisk to create (absolute path)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Query mount point to detect/describe ramdisk\n"); + fprintf(stderr, " %%%s -q /path/to/ramdisk\n", prog); + fprintf(stderr, " /proc/mounts lists all the ramdisks (and other disks)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Unmount ramdisk\n"); + fprintf(stderr, " %%%s -u /path/to/ramdisk\n", prog); + fprintf(stderr, "\n"); + exit(-1); +} + +int suitable_mountpoint(char *dir, struct stat *sb, struct statfs *sf) { + if (stat(ramdisk, sb) == -1) { /* does mount point exist? */ + syslog(LOG_ERR, "no mount point %s: %s\n", ramdisk, strerror(errno)); + return -1; + } + if (S_ISDIR(sb->st_mode) == 0) { /* has to be a directory */ + syslog(LOG_ERR, "mount point %s: not a directory\n", ramdisk); + return -1; + } + if (statfs(ramdisk, sf) == -1) { /* what kinda filesystem is it on? */ + syslog(LOG_ERR, "can't statfs %s: %s\n", ramdisk, strerror(errno)); + return -1; + } + return 0; +} + +#define KB 1024L +#define MB (1024*1024L) +#define GB (1024*1024*1024L) +int query_ramdisk(void) { + struct stat sb; struct statfs sf; + if (suitable_mountpoint(ramdisk, &sb, &sf) == -1) return -1; + if (sf.f_type != TMPFS_MAGIC) { + printf("%s: not a ramdisk\n", ramdisk); + return -1; + } + char szb[100]; + long bytes = sf.f_bsize*sf.f_blocks; + if (bytes < KB) snprintf(szb, sizeof(szb), "%ld bytes", bytes); + else if (bytes < MB) snprintf(szb, sizeof(szb), "%ld kb", bytes/KB); + else if (bytes < GB) snprintf(szb, sizeof(szb), "%ld mb", bytes/MB); + else snprintf(szb, sizeof(szb), "%ld gb", bytes/GB); + int used_pct = 100 - (sf.f_bfree * 100.0 / sf.f_blocks); + printf("%s: ramdisk of size %s (%d%% used)\n", ramdisk, szb, used_pct); +} + +int unmount_ramdisk(void) { + struct stat sb; struct statfs sf; + if (suitable_mountpoint(ramdisk, &sb, &sf) == -1) return -1; + if (sf.f_type != TMPFS_MAGIC) { + syslog(LOG_ERR,"%s: not a ramdisk\n", ramdisk); + return -1; + } + if (umount(ramdisk) == -1) { + syslog(LOG_ERR,"%s: cannot unmount\n", ramdisk); + return -1; + } + return 0; +} + +int create_ramdisk(void) { + int rc=-1; + char opts[100]; + + struct stat sb; struct statfs sf; + if (suitable_mountpoint(ramdisk, &sb, &sf) == -1) goto done; + if (sf.f_type == TMPFS_MAGIC) { rc=1; goto done; } /* already a ramdisk? */ + + /* ok, mount a ramdisk on this point */ + snprintf(opts,sizeof(opts),"size=%s",sz); + if ( (rc=mount("unused", ramdisk, "tmpfs", MS_NOATIME|MS_NODEV, opts))==-1) { + syslog(LOG_ERR, "can't make ramdisk %s: %s\n", ramdisk, strerror(errno)); + } + + done: + if (rc == 0) syslog(LOG_INFO,"mounted ramdisk %s (size %s)\n", ramdisk, sz); + else if (rc == 1) syslog(LOG_INFO,"ramdisk %s exists\n", ramdisk); + else if (rc == -1) syslog(LOG_ERR,"failed to make ramdisk %s\n", ramdisk); + return rc; +} + +void make_dirs(UT_array *dirs) { + char **d, *dir; + d=NULL; + while ( (d=(char**)utarray_next(dirs,d))) { + dir = *d; + /* fprintf(stderr,"dir is %s\n",dir); */ + if (mkdir(dir, 0777) == -1) { + fprintf(stderr,"failed to make %s: %s\n",dir,strerror(errno)); + } + } +} + +int main(int argc, char * argv[]) { + int opt, rc; + utarray_new(dirs,&ut_str_icd); + + while ( (opt = getopt(argc, argv, "v+cqus:hd:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'q': if (mode) usage(argv[0]); mode=MODE_QUERY; break; + case 'c': if (mode) usage(argv[0]); mode=MODE_CREATE; break; + case 'u': if (mode) usage(argv[0]); mode=MODE_UNMOUNT; break; + case 's': sz=strdup(optarg); break; + case 'd': utarray_push_back(dirs,&optarg); break; + case 'h': default: usage(argv[0]); break; + } + } + if (optind < argc) ramdisk=argv[optind++]; + if (!ramdisk) usage(argv[0]); + openlog("ramdisk", LOG_PID|LOG_PERROR, LOG_LOCAL0); + + switch(mode) { + case MODE_CREATE: rc=create_ramdisk(); make_dirs(dirs); break; + case MODE_UNMOUNT: rc=unmount_ramdisk(); break; + case MODE_QUERY: rc=query_ramdisk(); break; + default: usage(argv[0]); break; + } + utarray_free(dirs); + return rc; +} diff --git a/sysutils/ramdisk/utarray.h b/sysutils/ramdisk/utarray.h new file mode 100644 index 0000000..614a59e --- /dev/null +++ b/sysutils/ramdisk/utarray.h @@ -0,0 +1,226 @@ +/* +Copyright (c) 2008-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + * see http://uthash.sourceforge.net/utarray + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.4 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + const UT_icd *icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + utarray_reserve(a,1); \ + if (j > (a)->i) break; \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) break; \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd->sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd->dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd->init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd->init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr(a,pos), _utarray_eltptr(a,pos+len), \ + ((a->i)-(pos+len))*((a)->icd->sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd->sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/sysutils/sized/.gitignore b/sysutils/sized/.gitignore new file mode 100644 index 0000000..2992b6e --- /dev/null +++ b/sysutils/sized/.gitignore @@ -0,0 +1 @@ +sized diff --git a/sysutils/sized/Makefile b/sysutils/sized/Makefile new file mode 100644 index 0000000..b06277b --- /dev/null +++ b/sysutils/sized/Makefile @@ -0,0 +1,15 @@ +OBJS=sized +all: $(OBJS) +CFLAGS=-I../logd -g +LIBS=-L../logd -llogc + +sized: sized.c + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +.PHONY: clean + +clean: + rm -f *.o $(OBJS) + +install: $(OBJS) + cp $(OBJS) /usr/local/bin diff --git a/sysutils/sized/sized.c b/sysutils/sized/sized.c new file mode 100644 index 0000000..6b0b2dc --- /dev/null +++ b/sysutils/sized/sized.c @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "logc.h" +#include "utarray.h" +#include "utstring.h" + +/****************************************************************************** + * sized + * a utility to keep a directory under a certain size by deleting old files + *****************************************************************************/ +const char *modname = "sized"; +#define PERIODIC_SCAN_INTERVAL (10*1000) /* 10 sec, expressed in milliseconds */ + +/* command line configuration parameters */ +struct { + int verbose; + int once; + int continuous; + int query; + int dry_run; + char *sz; + long sz_bytes; + char *dir; +} cf = { + .sz="90%", +}; + +typedef struct { + int file_idx; + struct stat sb; +} file_stat_t; + +UT_icd stats_icd = {sizeof(file_stat_t), NULL, NULL, NULL}; +static int attrition_sort(const void *_a, const void *_b) { + file_stat_t *a = (file_stat_t*)_a; + file_stat_t *b = (file_stat_t*)_b; + /* oldest modify time sorts first */ + return a->sb.st_mtime - b->sb.st_mtime; +} + +void usage(char *prog) { + fprintf(stderr, "usage:\n\n"); + fprintf(stderr, "Delete files to keep dir under size x\n"); + fprintf(stderr, " %s -o|-c [-vd] [-s 10g] dir\n", prog); + fprintf(stderr, " size is bytes, or suffixed with k|m|g|%% [def: 90%% of fs]\n"); + fprintf(stderr, " -o (once) run just once\n"); + fprintf(stderr, " -c (continuous) run indefinitely to maintain size\n"); + fprintf(stderr, " -d (dry run) do not remove any files, only print\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Query directory size\n"); + fprintf(stderr, " %s -q dir\n", prog); + fprintf(stderr, "\n"); + fprintf(stderr, "Note: recursion is not supported\n"); + fprintf(stderr, "\n"); + exit(-1); +} + +int get_files(UT_array *files, UT_array *stats) { + struct dirent *dent; + char *name, *path; + file_stat_t fsb; + int rc=-1,i=0; + DIR *d; + + UT_string *s; + utstring_new(s); + utarray_clear(files); + utarray_clear(stats); + + if ( (d = opendir(cf.dir)) == NULL) { + lm("failed to opendir [%s]: %s\n", cf.dir, strerror(errno)); + goto done; + } + + while ( (dent = readdir(d)) != NULL) { + if (dent->d_type != DT_REG) continue; + if (dent->d_name[0] == '.') continue; /* skip dot files */ + // ok, fully qualify it and push it + utstring_clear(s); + utstring_printf(s, "%s/%s", cf.dir, dent->d_name); + path = utstring_body(s); + if (stat(path,&fsb.sb) == -1) { + lm("can't stat %s: %s", path, strerror(errno)); + continue; + } + fsb.file_idx = i++; + utarray_push_back(files, &path); + utarray_push_back(stats, &fsb); + } + rc = 0; // success + + done: + utstring_free(s); + if (d) closedir(d); + return rc; +} + +int do_attrition(void) { + int rc = -1, nfiles=0; + UT_array *files; + UT_array *stats; + utarray_new(files,&ut_str_icd); + utarray_new(stats,&stats_icd); + if (get_files(files,stats) == -1) goto done; + + /* tally up their sizes */ + long total_sz=0; + file_stat_t *fs=NULL; + while ( (fs=(file_stat_t*)utarray_next(stats,fs))) total_sz += fs->sb.st_size; + if (total_sz < cf.sz_bytes) { rc = 0; goto done; } + + /* we're oversize. sort the files oldest first and delete til under max size*/ + utarray_sort(stats,attrition_sort); + fs=NULL; + while ( (fs=(file_stat_t*)utarray_next(stats,fs))) { + char *file = *(char**)utarray_eltptr(files, fs->file_idx); + if (cf.verbose) lm("removing %s (size %ld)", file, (long)fs->sb.st_size); + if (cf.dry_run || (unlink(file) == 0)) { + total_sz -= fs->sb.st_size; + nfiles++; + if (total_sz < cf.sz_bytes) { rc = 0; goto done; } + } else { + lm("can't unlink %s: %s", file, strerror(errno)); + } + } + + done: + if (cf.verbose) lm("%d files removed", nfiles); + utarray_free(files); + utarray_free(stats); + return rc; +} + +#define KB 1024L +#define MB (1024*1024L) +#define GB (1024*1024*1024L) +char *hsz(long bytes, char *szb, int szl) { + if (bytes < KB) snprintf(szb, szl, "%ld bytes", bytes); + else if (bytes < MB) snprintf(szb, szl, "%ld kb", bytes/KB); + else if (bytes < GB) snprintf(szb, szl, "%ld mb", bytes/MB); + else snprintf(szb, szl, "%ld gb", bytes/GB); + return szb; +} + +int do_query(void) { + int rc = -1; + UT_array *files; + UT_array *stats; + utarray_new(files,&ut_str_icd); + utarray_new(stats,&stats_icd); + if (get_files(files,stats) == -1) goto done; + + /* tally up their sizes */ + long total_sz=0; + file_stat_t *fs=NULL; + while ( (fs=(file_stat_t*)utarray_next(stats,fs))) total_sz += fs->sb.st_size; + + char tsz[100],csz[100]; + lm("directory size: %s (limit %s)", hsz(total_sz, tsz, sizeof(tsz)), + hsz(cf.sz_bytes, csz, sizeof(csz))); + + rc = 0; + + done: + utarray_free(files); + utarray_free(stats); + return rc; +} + +/* lookup the size of the filesystem underlying cf.dir and + * calculate pct% of that size */ +long get_fs_pct(int pct) { + assert(pct > 0 && pct < 100); + struct statfs fb; + if (statfs(cf.dir, &fb) == -1) { + lm("can't statfs %s: %s", cf.dir, strerror(errno)); + return -1; + } + long fsz = fb.f_bsize * fb.f_blocks; /* filesystem size */ + long cap = (fsz*pct) * 0.01; + //lm("fs size: %ld * %ld%% = cap %ld bytes", fsz, pct, cap); + return cap; +} + +/* convert something like "20%" or "20m" to bytes. + * percentage means 'percent of filesystem size' */ +long sztobytes(void) { + long n; int l; char unit; + if (sscanf(cf.sz,"%ld",&n) != 1) return -1; /* e.g. 20 from "20m" */ + l = strlen(cf.sz); unit = cf.sz[l-1]; + if (unit >= '0' && unit <= '9') return n; /* no unit suffix */ + switch(unit) { + default: return -1; break; + case '%': n = get_fs_pct(n); break; + case 't': n *= 1024; /* fall through */ + case 'g': n *= 1024; /* fall through */ + case 'm': n *= 1024; /* fall through */ + case 'k': n *= 1024; + } + return n; +} + +int clear_file_event(int fd) { + struct inotify_event *ev, *nx; + int rc; + size_t sz; + + union { + struct inotify_event ev; + char buf[sizeof(struct inotify_event) + PATH_MAX]; + } eb; + + rc = read(fd, &eb.ev, sizeof(eb)); + if (rc == -1) { + lm("inotify read failed: %s", strerror(errno)); + return -1; + } + for(ev = &eb.ev; rc > 0; ev = nx) { + + sz = sizeof(*ev) + ev->len; + nx = (struct inotify_event*)((char*)ev + sz); + rc -= sz; + + if (ev->mask & IN_UNMOUNT) { + lm("%s unmounted... exiting", cf.dir); + return -2; + } + } + + /* it's ok if we didn't completely clear it; epoll will notify us again */ + return 0; +} + +int main(int argc, char * argv[]) { + int opt, rc=0, ifd=-1,efd=-1,er,mask,wd; + + while ( (opt = getopt(argc, argv, "v+s:ocdqh")) != -1) { + switch (opt) { + case 'v': cf.verbose++; break; + case 'q': cf.query=1; break; + case 'c': cf.continuous=1; break; + case 'o': cf.once=1; break; + case 's': cf.sz=strdup(optarg); break; + case 'd': cf.dry_run=1; break; + case 'h': default: usage(argv[0]); break; + } + } + if (optind < argc) cf.dir=argv[optind++]; + if (!cf.dir) usage(argv[0]); + if (cf.query + cf.once + cf.continuous != 1) usage(argv[0]); /* exclusive */ + if ( (cf.sz_bytes=sztobytes()) == -1) usage(argv[0]); + if (cf.query) { do_query(); goto done; } + + if ( (rc=do_attrition()) == -1) goto done; + if (!cf.continuous) goto done; + + /* continuous mode */ + if ( (ifd = inotify_init()) == -1) { + lm("inotify_init failed: %s", strerror(errno)); + goto done; + } + mask = IN_CLOSE_WRITE|IN_UNMOUNT; + if ( (wd = inotify_add_watch(ifd, cf.dir, mask)) == -1) { + lm("inotify_add_watch failed"); + goto done; + } + /* wait for file events or periodic attrition */ + if ( (efd = epoll_create(5)) == -1) { + lm("epoll_create failed: %s", strerror(errno)); + goto done; + } + struct epoll_event ev = {.events = EPOLLIN, .data.fd=ifd}; + if (epoll_ctl(efd, EPOLL_CTL_ADD, ifd, &ev) == -1) { + lm("epoll_ctl failed: %s", strerror(errno)); + goto done; + } + do { + er = epoll_wait(efd, &ev, 1, PERIODIC_SCAN_INTERVAL); + switch(er) { + case -1: lm("epoll_wait error: %s", strerror(errno)); break; + case 1: if (clear_file_event(ifd) < 0) goto done; break; + case 0: /* got timeout */; break; + default: assert(0); break; + } + do_attrition(); + } while(er != -1); + + + done: + if (ifd != -1) close(ifd); + if (efd != -1) close(efd); + return rc; +} diff --git a/sysutils/sized/utarray.h b/sysutils/sized/utarray.h new file mode 100644 index 0000000..9466d03 --- /dev/null +++ b/sysutils/sized/utarray.h @@ -0,0 +1,224 @@ +/* +Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + * see http://uthash.sourceforge.net/utarray + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.1 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + const UT_icd *icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + utarray_reserve(a,1); \ + if (j > (a)->i) break; \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) break; \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd->sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd->dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd->init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd->init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta(dst,src,utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr(a,pos), _utarray_eltptr(a,pos+len), \ + ((a->i)-(pos+len))*((a)->icd->sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \ +} while(0) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/sysutils/sized/utstring.h b/sysutils/sized/utstring.h new file mode 100644 index 0000000..8b92097 --- /dev/null +++ b/sysutils/sized/utstring.h @@ -0,0 +1,138 @@ +/* +Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + * see http://uthash.sourceforge.net/utstring + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.1 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve(s,(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + s->i += l; \ + s->d[s->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve(dst,(src->i)+1); \ + if (src->i) memcpy(&(dst)->d[(dst)->i], src->d, src->i); \ + dst->i += src->i; \ + dst->d[dst->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && (n < (int)(s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +#endif /* UTSTRING_H */ diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..240dddd --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,2 @@ +*[0-9] +*.out diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..5ee6473 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,27 @@ +SRCS = $(wildcard test*.c) +PROGS = $(patsubst %.c,%,$(SRCS)) + +LIBDIR = .. +LIB = $(LIBDIR)/libts.a + +CFLAGS = -I$(LIBDIR) -fno-strict-aliasing +CFLAGS += -g +CFLAGS += -Wall +CFLAGS += ${EXTRA_CFLAGS} + +TEST_TARGET=run_tests +TESTS=./do_tests + +all: $(PROGS) $(TEST_TARGET) + +$(PROGS): $(LIB) + $(CC) $(CFLAGS) -o $@ $(@).c $(LIB) + +run_tests: $(PROGS) + perl $(TESTS) + +.PHONY: clean + +clean: + rm -f $(PROGS) test*.out + rm -rf *.dSYM diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..ce877dc --- /dev/null +++ b/tests/README @@ -0,0 +1,15 @@ +test1: initial key-value creation and free +test2: test key replacement +test3: test spooling out +test4: test spooling out, then a second set (append) +test5: test two spool writers locking separate spools +test6: test spool reopen logic when spool grows to max +test7: spool reader test +test8: test internal function that keeps filenames w/highest sequence numbers +test9: test programmatic reset +test10: test programmatic reset when another read has lock +test11: test kv_set_base +test12: test kv_statdir +test13: test kv_statdir +test14: test kv_statdir +test15: test zero-length NULL value and double diff --git a/tests/do_tests b/tests/do_tests new file mode 100755 index 0000000..574403f --- /dev/null +++ b/tests/do_tests @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/tests/test1.ans b/tests/test1.ans new file mode 100644 index 0000000..d94d75d --- /dev/null +++ b/tests/test1.ans @@ -0,0 +1,3 @@ +kv set has 2 items +key [hello], val [world] +key [second], val [life] diff --git a/tests/test1.c b/tests/test1.c new file mode 100644 index 0000000..84c2eae --- /dev/null +++ b/tests/test1.c @@ -0,0 +1,21 @@ +#include +#include "kvspool.h" + +int main() { + void *set = kv_set_new(); + /* add some kv pairs */ + kv_adds(set, "hello", "world"); + kv_adds(set, "second", "life"); + + /* see if it worked- count kv pairs */ + int len = kv_len(set); + printf("kv set has %d items\n", (int)len); + + /* loop over them */ + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf("key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + kv_set_free(set); + return 0; +} diff --git a/tests/test10.ans b/tests/test10.ans new file mode 100644 index 0000000..1b15190 --- /dev/null +++ b/tests/test10.ans @@ -0,0 +1,18 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +spooling second frame +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 122 +clear set +reading from spool +reader read frame: + key [hello], val [again] + key [second], val [life] +reader read frame: + key [hello], val [again] + key [second], val [time] +kv_spool_read returned 0 +resetting the spool directory for another round of reading +kv_spool_read returned 0 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 122 diff --git a/tests/test10.c b/tests/test10.c new file mode 100644 index 0000000..112c0ee --- /dev/null +++ b/tests/test10.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + + +/****************************************************************************** + * the test itself + *****************************************************************************/ +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + /* replace a value in the set, spool the set out. it should append + * to the spool file previously created. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "time"); + kv_spool_write(sp,set); + kv_spoolwriter_free(sp); + + /* verify spool has updated according to expectation */ + scan_spool(0); + + printf("clear set\n"); + kv_set_clear(set); + /* loop over them */ + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf("key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + + printf("reading from spool\n"); + /* now try reading the spool */ + sp = kv_spoolreader_new(dir,base); + int rc; + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame:\n"); + kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf(" key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + } + printf("kv_spool_read returned %d\n", rc); + //kv_spoolreader_free(sp); + + /* now reset it and read again */ + printf("resetting the spool directory for another round of reading\n"); + sp_reset(dir,base); + //sp = kv_spoolreader_new(dir,base); + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame:\n"); + kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf(" key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + } + printf("kv_spool_read returned %d\n", rc); + kv_spoolreader_free(sp); + + kv_set_free(set); + scan_spool(1); + return 0; +} diff --git a/tests/test11.ans b/tests/test11.ans new file mode 100644 index 0000000..05bec25 --- /dev/null +++ b/tests/test11.ans @@ -0,0 +1,5 @@ +reader read frame, base mybase +reader read frame, base mybase +wildcard base +reader read frame, base mybase +reader read frame, base mybase diff --git a/tests/test11.c b/tests/test11.c new file mode 100644 index 0000000..3e8b3e4 --- /dev/null +++ b/tests/test11.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "mybase"; + + +/****************************************************************************** + * the test itself + *****************************************************************************/ +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + int rc; + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + kv_adds(set, "hello", "there"); + kv_adds(set, "second", "world"); + kv_spool_write(sp,set); + kv_spoolwriter_free(sp); + + /* now try reading the spool */ + sp = kv_spoolreader_new(dir,base); + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame, base %s\n", kv_set_base(set)); + } + kv_spoolreader_free(sp); + + /* repeat the test for wildcard base */ + printf("wildcard base\n"); + sp_reset(dir,base); + sp = kv_spoolreader_new(dir,""); + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame, base %s\n", kv_set_base(set)); + } + kv_spoolreader_free(sp); + + kv_set_free(set); + return 0; +} diff --git a/tests/test12.ans b/tests/test12.ans new file mode 100644 index 0000000..b7180fe --- /dev/null +++ b/tests/test12.ans @@ -0,0 +1,13 @@ +spooling second frame +2 stat records: +abe 0 +bob 0 +2 stat records: +abe 45 +bob 100 +file abe.**********.***-*.sr, len 4 +file abe.**********.***-*.sr, len 4 +file bob.**********.***-*.sr, len 4 +file abe.**********.***-*.sp, len 65 +file abe.**********.***-*.sp, len 75 +file bob.**********.***-*.sp, len 75 diff --git a/tests/test12.c b/tests/test12.c new file mode 100644 index 0000000..78cdc67 --- /dev/null +++ b/tests/test12.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "abe"; +char *base2 = "bob"; + +int main(int argc, char *argv[]) { + int i,rc; + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + + /* create a second spoolwriter in the same directory. + * because the first spoolwriter has a lock on the file it contains, + * this spoolwriter should create its own file, rather than append. */ + void *sp2 = kv_spoolwriter_new(dir,base); + if (!sp2) exit(-1); + /* replace a value in the set, spool the set out. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "new spool file"); + kv_spool_write(sp2,set); + + /* spool a set out to another base. this should make the third spoolfile */ + void *sp3 = kv_spoolwriter_new(dir,base2); + if (!sp3) exit(-1); + kv_spool_write(sp3,set); + + /* statdir now should have two records (base and base2) both 0% consumed */ + kv_stat_t *stats; + rc = kv_stat(dir,NULL,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + /* consume some */ + void *sp4 = kv_spoolreader_new(dir,base); kv_spool_read(sp4,set,0); /* 50% */ + void *sp5 = kv_spoolreader_new(dir,base2); kv_spool_read(sp5,set,0); /*100% */ + + /* view the stats now */ + rc = kv_stat(dir,NULL,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + //printf("dir is %s\n",dir); sleep(100); + + kv_spoolwriter_free(sp); + kv_spoolwriter_free(sp2); + kv_spoolwriter_free(sp3); + kv_spoolreader_free(sp4); + kv_spoolreader_free(sp5); + kv_set_free(set); + + /* verify spool has updated according to expectation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test13.ans b/tests/test13.ans new file mode 100644 index 0000000..be0a1ac --- /dev/null +++ b/tests/test13.ans @@ -0,0 +1,11 @@ +0 stat records: +1 stat records: +exeter 100 +exeter 0 +exeter 33 +exeter 66 +exeter 50 +exeter 75 +exeter 100 +file exeter.**********.***-*.sr, len 4 +file exeter.**********.***-*.sp, len 236 diff --git a/tests/test13.c b/tests/test13.c new file mode 100644 index 0000000..1ce5889 --- /dev/null +++ b/tests/test13.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "exeter"; +char *base2 = "leeds"; + +int main(int argc, char *argv[]) { + int i,rc; + + kv_stat_t *stats; + char *dir = mktmpdir(); + + /* shouldn't have any stats yet */ + rc = kv_stat(dir,NULL,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + /* should have one stats record, an empty spool (by definition 100% consumed) */ + rc = kv_stat(dir,NULL,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); /* record 1 */ + kv_spool_write(sp,set); /* record 2 */ + kv_spool_write(sp,set); /* record 3 */ + + /* should have one stats record, now 0% consumed */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + void *sp2 = kv_spoolreader_new(dir,base); + kv_spool_read(sp2,set,0); /* 33% */ + + /* should have one stats record, now 33% consumed */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spool_read(sp2,set,0); /* 66% */ + + /* should have one stats record, now 66% consumed */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spool_write(sp,set); /* record 4 */ + + /* we still only consumed two records (but there are now 4) so 50% */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spool_read(sp2,set,0); /* 75% */ + + /* we consumed three records (of 4) so 75% */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spool_read(sp2,set,0); /* 100% */ + + /* should have one stats record, now 100% consumed */ + rc = kv_stat(dir,NULL,&stats); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spoolwriter_free(sp); + kv_spoolreader_free(sp2); + kv_set_free(set); + + /* verify spool has updated according to expectation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test14.ans b/tests/test14.ans new file mode 100644 index 0000000..0a08f39 --- /dev/null +++ b/tests/test14.ans @@ -0,0 +1,13 @@ +spooling second frame +1 stat records: +abe 0 +1 stat records: +abe 45 +1 stat records: +bob 100 +file abe.**********.***-*.sr, len 4 +file abe.**********.***-*.sr, len 4 +file bob.**********.***-*.sr, len 4 +file abe.**********.***-*.sp, len 65 +file abe.**********.***-*.sp, len 75 +file bob.**********.***-*.sp, len 75 diff --git a/tests/test14.c b/tests/test14.c new file mode 100644 index 0000000..9507068 --- /dev/null +++ b/tests/test14.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "abe"; +char *base2 = "bob"; + +int main(int argc, char *argv[]) { + int i,rc; + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + + /* create a second spoolwriter in the same directory. + * because the first spoolwriter has a lock on the file it contains, + * this spoolwriter should create its own file, rather than append. */ + void *sp2 = kv_spoolwriter_new(dir,base); + if (!sp2) exit(-1); + /* replace a value in the set, spool the set out. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "new spool file"); + kv_spool_write(sp2,set); + + /* spool a set out to another base. this should make the third spoolfile */ + void *sp3 = kv_spoolwriter_new(dir,base2); + if (!sp3) exit(-1); + kv_spool_write(sp3,set); + + /* statdir now should have two records (base and base2) both 0% consumed */ + kv_stat_t *stats; + rc = kv_stat(dir,base,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + /* consume some */ + void *sp4 = kv_spoolreader_new(dir,base); kv_spool_read(sp4,set,0); /* 50% */ + void *sp5 = kv_spoolreader_new(dir,base2); kv_spool_read(sp5,set,0); /*100% */ + + /* view the stats now */ + rc = kv_stat(dir,base,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + /* view the stats now for other base */ + rc = kv_stat(dir,base2,&stats); + printf("%d stat records:\n", rc); + for(i=0; i < rc; i++) printf("%s %d\n", stats[i].base, stats[i].pct_consumed); + if (stats) free(stats); + + kv_spoolwriter_free(sp); + kv_spoolwriter_free(sp2); + kv_spoolwriter_free(sp3); + kv_spoolreader_free(sp4); + kv_spoolreader_free(sp5); + kv_set_free(set); + + /* verify spool has updated according to expectation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test15.c b/tests/test15.c new file mode 100644 index 0000000..29bd4cd --- /dev/null +++ b/tests/test15.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + +int main(int argc, char *argv[]) { + double pi = 3.14159; + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_addt(set, "vnull", 'b', NULL, 0); + kv_addt(set, "adouble", 'f', &pi, sizeof(double)); + kv_spool_write(sp,set); + kv_set_free(set); + + kv_spoolwriter_free(sp); + + /* scan spool to validate expected file creation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test2.ans b/tests/test2.ans new file mode 100644 index 0000000..20e4981 --- /dev/null +++ b/tests/test2.ans @@ -0,0 +1,3 @@ +kv set has 2 items +key [hello], val [new] +key [second], val [life] diff --git a/tests/test2.c b/tests/test2.c new file mode 100644 index 0000000..339b896 --- /dev/null +++ b/tests/test2.c @@ -0,0 +1,22 @@ +#include +#include "kvspool.h" + +int main() { + void *set = kv_set_new(); + /* add some kv pairs */ + kv_adds(set, "hello", "world"); + kv_adds(set, "second", "life"); + kv_adds(set, "hello", "new"); + + /* see if it worked- count kv pairs */ + int len = kv_len(set); + printf("kv set has %d items\n", (int)len); + + /* loop over them */ + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf("key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + kv_set_free(set); + return 0; +} diff --git a/tests/test3.ans b/tests/test3.ans new file mode 100644 index 0000000..e5b22d8 --- /dev/null +++ b/tests/test3.ans @@ -0,0 +1,2 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 diff --git a/tests/test3.c b/tests/test3.c new file mode 100644 index 0000000..4b4a065 --- /dev/null +++ b/tests/test3.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + kv_set_free(set); + + kv_spoolwriter_free(sp); + + /* scan spool to validate expected file creation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test4.ans b/tests/test4.ans new file mode 100644 index 0000000..75df372 --- /dev/null +++ b/tests/test4.ans @@ -0,0 +1,5 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +spooling second frame +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 122 diff --git a/tests/test4.c b/tests/test4.c new file mode 100644 index 0000000..8470f93 --- /dev/null +++ b/tests/test4.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + /* replace a value in the set, spool the set out. it should append + * to the spool file previously created. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "time"); + kv_spool_write(sp,set); + kv_spoolwriter_free(sp); + kv_set_free(set); + + /* verify spool has updated according to expectation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test5.ans b/tests/test5.ans new file mode 100644 index 0000000..731ebba --- /dev/null +++ b/tests/test5.ans @@ -0,0 +1,7 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +spooling second frame +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +file spool.**********.***-*.sp, len 75 diff --git a/tests/test5.c b/tests/test5.c new file mode 100644 index 0000000..b25c79d --- /dev/null +++ b/tests/test5.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + /* create a second spoolwriter in the same directory. + * because the first spoolwriter has a lock on the file it contains, + * this spoolwriter should create its own file, rather than append. */ + void *sp2 = kv_spoolwriter_new(dir,base); + if (!sp2) exit(-1); + /* replace a value in the set, spool the set out. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "new spool file"); + kv_spool_write(sp2,set); + kv_spoolwriter_free(sp); + kv_spoolwriter_free(sp2); + kv_set_free(set); + + /* verify spool has updated according to expectation */ + scan_spool(1); + + return 0; +} diff --git a/tests/test6.ans b/tests/test6.ans new file mode 100644 index 0000000..4933fe8 --- /dev/null +++ b/tests/test6.ans @@ -0,0 +1,49 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +spooling 20000 more frames +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 196316 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +spooling 20000 more frames +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 77984 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +spooling 20000 more frames +file spool.**********.***-*.sr, len 4 +file spool.**********.***-**.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-**.sp, len 274235 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 +file spool.**********.***-*.sp, len 314591 diff --git a/tests/test6.c b/tests/test6.c new file mode 100644 index 0000000..406e322 --- /dev/null +++ b/tests/test6.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; +int main(int argc, char *argv[]) { + + /* customize the spool options */ + kv_spool_options.dir_max = 3*1024*1024; /* 3 mb */ + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + int i, num_spoolouts = 20000; + /* one set is about 54 bytes so it takes that many to exceed the 1mb + spool max size and induce creation of a second spool file */ + printf("spooling %d more frames\n", num_spoolouts); + for(i=0; i +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + + +/****************************************************************************** + * the test itself + *****************************************************************************/ +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + /* replace a value in the set, spool the set out. it should append + * to the spool file previously created. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "time"); + kv_spool_write(sp,set); + kv_spoolwriter_free(sp); + + /* verify spool has updated according to expectation */ + scan_spool(0); + + printf("clear set\n"); + kv_set_clear(set); + /* loop over them */ + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf("key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + + printf("reading from spool\n"); + /* now try reading the spool */ + sp = kv_spoolreader_new(dir,base); + int rc; + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame:\n"); + kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf(" key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + } + printf("kv_spool_read returned %d\n", rc); + kv_spoolreader_free(sp); + kv_set_free(set); + scan_spool(1); + return 0; +} diff --git a/tests/test8.ans b/tests/test8.ans new file mode 100644 index 0000000..4db87bd --- /dev/null +++ b/tests/test8.ans @@ -0,0 +1,3 @@ +spool.1234567.111-000.sp +spool.1234567.222-002.sp +spool.1234567.333-002.sp diff --git a/tests/test8.c b/tests/test8.c new file mode 100644 index 0000000..c4c2b32 --- /dev/null +++ b/tests/test8.c @@ -0,0 +1,23 @@ +#include +#include "kvspool_internal.h" +#include "utarray.h" + + +int main(int argc, char * argv[] ) { + char *f, **p; + UT_array *files; + utarray_new(files,&ut_str_icd); + + f="spool.1234567.111-000.sp"; utarray_push_back(files,&f); + f="spool.1234567.222-001.sp"; utarray_push_back(files,&f); + f="spool.1234567.222-002.sp"; utarray_push_back(files,&f); + f="spool.1234567.333-002.sp"; utarray_push_back(files,&f); + + sp_keep_maxseq(files); + p=NULL; + while ( (p=(char**)utarray_next(files,p))) { + printf("%s\n",*p); + } + utarray_free(files); + return 0; +} diff --git a/tests/test9.ans b/tests/test9.ans new file mode 100644 index 0000000..3d9bc4d --- /dev/null +++ b/tests/test9.ans @@ -0,0 +1,24 @@ +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 65 +spooling second frame +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 122 +clear set +reading from spool +reader read frame: + key [hello], val [again] + key [second], val [life] +reader read frame: + key [hello], val [again] + key [second], val [time] +kv_spool_read returned 0 +resetting the spool directory for another round of reading +reader read frame: + key [hello], val [again] + key [second], val [life] +reader read frame: + key [hello], val [again] + key [second], val [time] +kv_spool_read returned 0 +file spool.**********.***-*.sr, len 4 +file spool.**********.***-*.sp, len 122 diff --git a/tests/test9.c b/tests/test9.c new file mode 100644 index 0000000..455eeba --- /dev/null +++ b/tests/test9.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utils.h" + +char *base = "spool"; + + +/****************************************************************************** + * the test itself + *****************************************************************************/ +int main(int argc, char *argv[]) { + + char *dir = mktmpdir(); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + kv_adds(set, "hello", "again"); + kv_adds(set, "second", "life"); + kv_spool_write(sp,set); + + /* scan spool to validate expected file creation */ + scan_spool(0); + + /* replace a value in the set, spool the set out. it should append + * to the spool file previously created. */ + printf("spooling second frame\n"); + kv_adds(set, "second", "time"); + kv_spool_write(sp,set); + kv_spoolwriter_free(sp); + + /* verify spool has updated according to expectation */ + scan_spool(0); + + printf("clear set\n"); + kv_set_clear(set); + /* loop over them */ + kv_t *kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf("key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + + printf("reading from spool\n"); + /* now try reading the spool */ + sp = kv_spoolreader_new(dir,base); + int rc; + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame:\n"); + kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf(" key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + } + printf("kv_spool_read returned %d\n", rc); + kv_spoolreader_free(sp); + + /* now reset it and read again */ + printf("resetting the spool directory for another round of reading\n"); + sp_reset(dir,base); + sp = kv_spoolreader_new(dir,base); + while ( (rc=kv_spool_read(sp, set, 0)) == 1) { + printf("reader read frame:\n"); + kv = NULL; + while ( (kv = kv_next(set, kv))) { + printf(" key [%.*s], val [%.*s]\n", kv->klen, kv->key, kv->vlen, kv->val); + } + } + printf("kv_spool_read returned %d\n", rc); + kv_spoolreader_free(sp); + + kv_set_free(set); + scan_spool(1); + return 0; +} diff --git a/tests/utils.c b/tests/utils.c new file mode 100644 index 0000000..49e2a59 --- /dev/null +++ b/tests/utils.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" + +/****************************************************************************** + * boilerplate utilities for test + *****************************************************************************/ +static char *wild = "*"; +static char dir[100]; +static void cleanup(void) { chdir("/tmp"); if (*dir) rmdir(dir); } +char* mktmpdir(void) { + snprintf(dir,sizeof(dir),"/tmp/test.%d", (int)getpid()); + mkdir(dir,0777); + atexit(cleanup); + return dir; +} +/* change digits to '-', used to normalize output for automated tests */ +static char *blot(char*c) { + char *s; + for(s=c; *s != '\0'; s++) { if ((*s >= '0') && (*s <= '9')) *s='*'; } + return c; +} + +static int strsort(const void *_a, const void *_b) { + char *a = *(char**)_a; + char *b = *(char**)_b; + return strcmp(a,b); +} +typedef struct { + int file_idx; + int file_len; +} file_xtra; +static UT_icd xtra_icd = {sizeof(file_xtra),NULL,NULL,NULL}; +static int xtrasort(const void *_a, const void *_b) { + file_xtra *a = (file_xtra*)_a; + file_xtra *b = (file_xtra*)_b; + return (a->file_len - b->file_len); +} +void scan_spool(int do_unlink) { + int i; + glob_t g; + struct stat sb; + UT_array *files; + UT_array *xtras; + utarray_new(files,&ut_str_icd); + utarray_new(xtras,&xtra_icd); + char **f, *file; + file_xtra x, *xp; + + if (chdir(dir) == -1) exit(-1); + glob(wild, 0, NULL, &g); + for(i=0; i < g.gl_pathc; i++) { + utarray_push_back(files, &g.gl_pathv[i]); + } + utarray_sort(files, strsort); + + f=NULL; + while ( (f=(char**)utarray_next(files,f))) { + file = *f; + stat(file,&sb); + if (do_unlink) unlink(file); + x.file_idx = utarray_eltidx(files,f); + x.file_len = sb.st_size; + utarray_push_back(xtras, &x); + } + utarray_sort(xtras, xtrasort); + xp=NULL; + while ( (xp=(file_xtra*)utarray_next(xtras,xp))) { + f = (char**)utarray_eltptr(files,xp->file_idx); + file = *f; + printf("file %s, len %d\n", blot(file),xp->file_len); + } + globfree(&g); + utarray_free(files); + utarray_free(xtras); +} + diff --git a/tests/utils.h b/tests/utils.h new file mode 100644 index 0000000..870d37b --- /dev/null +++ b/tests/utils.h @@ -0,0 +1,3 @@ + +char* mktmpdir(void); +void scan_spool(int do_unlink); diff --git a/tpl.c b/tpl.c new file mode 100644 index 0000000..5429af1 --- /dev/null +++ b/tpl.c @@ -0,0 +1,2479 @@ +/* +Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define TPL_VERSION 1.5 + +static const char id[]="$Id: tpl.c 192 2009-04-24 10:35:30Z thanson $"; + + +#include /* malloc */ +#include /* va_list */ +#include /* memcpy, memset, strchr */ +#include /* printf (tpl_hook.oops default function) */ + +#ifndef _WIN32 +#include /* for ftruncate */ +#else +#include +#define ftruncate(x,y) _chsize(x,y) +#endif +#include /* for 'open' */ +#include /* for 'open' */ +#include /* for 'open' */ +#include +#ifndef _WIN32 +#include /* uint32_t, uint64_t, etc */ +#else +typedef unsigned short ushort; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + + +#if ( defined __CYGWIN__ || defined __MINGW32__ || defined _WIN32 ) +#include "win/mman.h" /* mmap */ +#else +#include /* mmap */ +#endif + +#include "tpl.h" + +#define TPL_GATHER_BUFLEN 8192 +#define TPL_MAGIC "tpl" + +/* macro to add a structure to a doubly-linked list */ +#define DL_ADD(head,add) \ + do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ + } while (0); + +#define fatal_oom() tpl_hook.fatal("out of memory\n") + +/* bit flags (internal). preceded by the external flags in tpl.h */ +#define TPL_WRONLY (1 << 9) /* app has initiated tpl packing */ +#define TPL_RDONLY (1 << 10) /* tpl was loaded (for unpacking) */ +#define TPL_XENDIAN (1 << 11) /* swap endianness when unpacking */ +#define TPL_OLD_STRING_FMT (1 << 12) /* tpl has strings in 1.2 format */ + +/* values for the flags byte that appears after the magic prefix */ +#define TPL_SUPPORTED_BITFLAGS 3 +#define TPL_FL_BIGENDIAN (1 << 0) +#define TPL_FL_NULLSTRINGS (1 << 1) + +/* char values for node type */ +#define TPL_TYPE_ROOT 0 +#define TPL_TYPE_INT32 1 +#define TPL_TYPE_UINT32 2 +#define TPL_TYPE_BYTE 3 +#define TPL_TYPE_STR 4 +#define TPL_TYPE_ARY 5 +#define TPL_TYPE_BIN 6 +#define TPL_TYPE_DOUBLE 7 +#define TPL_TYPE_INT64 8 +#define TPL_TYPE_UINT64 9 +#define TPL_TYPE_INT16 10 +#define TPL_TYPE_UINT16 11 +#define TPL_TYPE_POUND 12 + +/* error codes */ +#define ERR_NOT_MINSIZE (-1) +#define ERR_MAGIC_MISMATCH (-2) +#define ERR_INCONSISTENT_SZ (-3) +#define ERR_FMT_INVALID (-4) +#define ERR_FMT_MISSING_NUL (-5) +#define ERR_FMT_MISMATCH (-6) +#define ERR_FLEN_MISMATCH (-7) +#define ERR_INCONSISTENT_SZ2 (-8) +#define ERR_INCONSISTENT_SZ3 (-9) +#define ERR_INCONSISTENT_SZ4 (-10) +#define ERR_UNSUPPORTED_FLAGS (-11) + +/* access to A(...) nodes by index */ +typedef struct tpl_pidx { + struct tpl_node *node; + struct tpl_pidx *next,*prev; +} tpl_pidx; + +/* A(...) node datum */ +typedef struct tpl_atyp { + uint32_t num; /* num elements */ + size_t sz; /* size of each backbone's datum */ + struct tpl_backbone *bb,*bbtail; + void *cur; +} tpl_atyp; + +/* backbone to extend A(...) lists dynamically */ +typedef struct tpl_backbone { + struct tpl_backbone *next; + /* when this structure is malloc'd, extra space is alloc'd at the + * end to store the backbone "datum", and data points to it. */ +#if __STDC_VERSION__ < 199901 + char *data; +#else + char data[]; +#endif +} tpl_backbone; + +/* mmap record */ +typedef struct tpl_mmap_rec { + int fd; + void *text; + size_t text_sz; +} tpl_mmap_rec; + +/* root node datum */ +typedef struct tpl_root_data { + int flags; + tpl_pidx *pidx; + tpl_mmap_rec mmap; + char *fmt; + int *fxlens, num_fxlens; +} tpl_root_data; + +/* node type to size mapping */ +struct tpl_type_t { + char c; + int sz; +}; + + +/* Internal prototypes */ +static tpl_node *tpl_node_new(tpl_node *parent); +static tpl_node *tpl_find_i(tpl_node *n, int i); +static void *tpl_cpv(void *datav, void *data, size_t sz); +static void *tpl_extend_backbone(tpl_node *n); +static char *tpl_fmt(tpl_node *r); +static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv); +static size_t tpl_ser_osz(tpl_node *n); +static void tpl_free_atyp(tpl_node *n,tpl_atyp *atyp); +static int tpl_dump_to_mem(tpl_node *r, void *addr, size_t sz); +static int tpl_mmap_file(char *filename, tpl_mmap_rec *map_rec); +static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out); +static int tpl_cpu_bigendian(void); +static int tpl_needs_endian_swap(void *); +static void tpl_byteswap(void *word, int len); +static void tpl_fatal(char *fmt, ...); +static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen); +static int tpl_unpackA0(tpl_node *r); +static int tpl_oops(const char *fmt, ...); +static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); +static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); +static int tpl_gather_blocking(int fd, void **img, size_t *sz); +static tpl_node *tpl_map_va(char *fmt, va_list ap); + +/* This is used internally to help calculate padding when a 'double' + * follows a smaller datatype in a structure. Normally under gcc + * on x86, d will be aligned at +4, however use of -malign-double + * causes d to be aligned at +8 (this is actually faster on x86). + * Also SPARC and x86_64 seem to align always on +8. + */ +struct tpl_double_alignment_detector { + char a; + double d; /* some platforms align this on +4, others on +8 */ +}; + +/* this is another case where alignment varies. mac os x/gcc was observed + * to align the int64_t at +4 under -m32 and at +8 under -m64 */ +struct tpl_int64_alignment_detector { + int i; + int64_t j; /* some platforms align this on +4, others on +8 */ +}; + +typedef struct { + size_t inter_elt_len; /* padded inter-element len; i.e. &a[1].field - &a[0].field */ + tpl_node *iter_start_node; /* node to jump back to, as we start each new iteration */ + size_t iternum; /* current iteration number (total req'd. iter's in n->num) */ +} tpl_pound_data; + +/* Hooks for customizing tpl mem alloc, error handling, etc. Set defaults. */ +tpl_hook_t tpl_hook = { + /* .oops = */ tpl_oops, + /* .malloc = */ malloc, + /* .realloc = */ realloc, + /* .free = */ free, + /* .fatal = */ tpl_fatal, + /* .gather_max = */ 0 /* max tpl size (bytes) for tpl_gather */ +}; + +static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */ +static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */ +static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */ +static const struct tpl_type_t tpl_types[] = { + /* [TPL_TYPE_ROOT] = */ {'r', 0}, + /* [TPL_TYPE_INT32] = */ {'i', sizeof(int32_t)}, + /* [TPL_TYPE_UINT32] = */ {'u', sizeof(uint32_t)}, + /* [TPL_TYPE_BYTE] = */ {'c', sizeof(char)}, + /* [TPL_TYPE_STR] = */ {'s', sizeof(char*)}, + /* [TPL_TYPE_ARY] = */ {'A', 0}, + /* [TPL_TYPE_BIN] = */ {'B', 0}, + /* [TPL_TYPE_DOUBLE] = */ {'f', 8}, /* not sizeof(double) as that varies */ + /* [TPL_TYPE_INT64] = */ {'I', sizeof(int64_t)}, + /* [TPL_TYPE_UINT64] = */ {'U', sizeof(uint64_t)}, + /* [TPL_TYPE_INT16] = */ {'j', sizeof(int16_t)}, + /* [TPL_TYPE_UINT16] = */ {'v', sizeof(uint16_t)}, + /* [TPL_TYPE_POUND] = */ {'#', 0}, +}; + +/* default error-reporting function. Just writes to stderr. */ +static int tpl_oops(const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + vfprintf(stderr,fmt,ap); + va_end(ap); + return 0; +} + + +static tpl_node *tpl_node_new(tpl_node *parent) { + tpl_node *n; + if ((n=tpl_hook.malloc(sizeof(tpl_node))) == NULL) { + fatal_oom(); + } + n->addr=NULL; + n->data=NULL; + n->num=1; + n->ser_osz=0; + n->children=NULL; + n->next=NULL; + n->parent=parent; + return n; +} + +/* Used in S(..) formats to pack several fields from a structure based on + * only the structure address. We need to calculate field addresses + * manually taking into account the size of the fields and intervening padding. + * The wrinkle is that double is not normally aligned on x86-32 but the + * -malign-double compiler option causes it to be. Double are aligned + * on Sparc, and apparently on 64 bit x86. We use a helper structure + * to detect whether double is aligned in this compilation environment. + */ +char *calc_field_addr(tpl_node *parent, int type,char *struct_addr, int ordinal) { + tpl_node *prev; + int offset; + int align_sz; + + if (ordinal == 1) return struct_addr; /* first field starts on structure address */ + + /* generate enough padding so field addr is divisible by it's align_sz. 4, 8, etc */ + prev = parent->children->prev; + switch(type) { + case TPL_TYPE_DOUBLE: + align_sz = sizeof(struct tpl_double_alignment_detector) > 12 ? 8 : 4; + break; + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + align_sz = sizeof(struct tpl_int64_alignment_detector) > 12 ? 8 : 4; + break; + default: + align_sz = tpl_types[type].sz; + break; + } + offset = ((uintptr_t)prev->addr - (uintptr_t)struct_addr) + + (tpl_types[prev->type].sz * prev->num); + offset = (offset + align_sz - 1) / align_sz * align_sz; + return struct_addr + offset; +} + +TPL_API tpl_node *tpl_map(char *fmt,...) { + va_list ap; + tpl_node *tn; + + va_start(ap,fmt); + tn = tpl_map_va(fmt, ap); + va_end(ap); + return tn; +} + +static tpl_node *tpl_map_va(char *fmt, va_list ap) { + int lparen_level=0,expect_lparen=0,t=0,in_structure=0,ordinal=0; + int in_nested_structure=0; + char *c, *peek, *struct_addr=NULL, *struct_next; + tpl_node *root,*parent,*n=NULL,*preceding,*iter_start_node=NULL, + *struct_widest_node=NULL, *np; tpl_pidx *pidx; + tpl_pound_data *pd; + int *fxlens, num_fxlens, pound_num, pound_prod, applies_to_struct; + int contig_fxlens[10]; /* temp space for contiguous fxlens */ + int num_contig_fxlens, i, j; + ptrdiff_t inter_elt_len=0; /* padded element length of contiguous structs in array */ + + + root = tpl_node_new(NULL); + root->type = TPL_TYPE_ROOT; + root->data = (tpl_root_data*)tpl_hook.malloc(sizeof(tpl_root_data)); + if (!root->data) fatal_oom(); + memset((tpl_root_data*)root->data,0,sizeof(tpl_root_data)); + + /* set up root nodes special ser_osz to reflect overhead of preamble */ + root->ser_osz = sizeof(uint32_t); /* tpl leading length */ + root->ser_osz += strlen(fmt) + 1; /* fmt + NUL-terminator */ + root->ser_osz += 4; /* 'tpl' magic prefix + flags byte */ + + parent=root; + + c=fmt; + while (*c != '\0') { + switch (*c) { + case 'c': + case 'i': + case 'u': + case 'j': + case 'v': + case 'I': + case 'U': + case 'f': + if (*c=='c') t=TPL_TYPE_BYTE; + else if (*c=='i') t=TPL_TYPE_INT32; + else if (*c=='u') t=TPL_TYPE_UINT32; + else if (*c=='j') t=TPL_TYPE_INT16; + else if (*c=='v') t=TPL_TYPE_UINT16; + else if (*c=='I') t=TPL_TYPE_INT64; + else if (*c=='U') t=TPL_TYPE_UINT64; + else if (*c=='f') t=TPL_TYPE_DOUBLE; + + if (expect_lparen) goto fail; + n = tpl_node_new(parent); + n->type = t; + if (in_structure) { + if (ordinal == 1) { + /* for S(...)# iteration. Apply any changes to case 's' too!!! */ + iter_start_node = n; + struct_widest_node = n; + } + if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) { + struct_widest_node = n; + } + n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++); + } else n->addr = (void*)va_arg(ap,void*); + n->data = tpl_hook.malloc(tpl_types[t].sz); + if (!n->data) fatal_oom(); + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz; + DL_ADD(parent->children,n); + break; + case 's': + if (expect_lparen) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_STR; + if (in_structure) { + if (ordinal == 1) { + iter_start_node = n; /* for S(...)# iteration */ + struct_widest_node = n; + } + if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) { + struct_widest_node = n; + } + n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++); + } else n->addr = (void*)va_arg(ap,void*); + n->data = tpl_hook.malloc(sizeof(char*)); + if (!n->data) fatal_oom(); + *(char**)(n->data) = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*); + DL_ADD(parent->children,n); + break; + case '#': + /* apply a 'num' to preceding atom */ + if (!parent->children) goto fail; + preceding = parent->children->prev; /* first child's prev is 'last child'*/ + t = preceding->type; + applies_to_struct = (*(c-1) == ')') ? 1 : 0; + if (!applies_to_struct) { + if (!(t == TPL_TYPE_BYTE || t == TPL_TYPE_INT32 || + t == TPL_TYPE_UINT32 || t == TPL_TYPE_DOUBLE || + t == TPL_TYPE_UINT64 || t == TPL_TYPE_INT64 || + t == TPL_TYPE_UINT16 || t == TPL_TYPE_INT16 || + t == TPL_TYPE_STR )) goto fail; + } + /* count up how many contiguous # and form their product */ + pound_prod=1; + num_contig_fxlens=0; + for(peek=c; *peek == '#'; peek++) { + pound_num = va_arg(ap, int); + if (pound_num < 1) { + tpl_hook.fatal("non-positive iteration count %d\n", pound_num); + } + if (num_contig_fxlens >= (sizeof(contig_fxlens)/sizeof(contig_fxlens[0]))) { + tpl_hook.fatal("contiguous # exceeds hardcoded limit\n"); + } + contig_fxlens[num_contig_fxlens++] = pound_num; + pound_prod *= pound_num; + } + /* increment c to skip contiguous # so its points to last one */ + c = peek-1; + /* differentiate atom-# from struct-# by noting preceding rparen */ + if (applies_to_struct) { /* insert # node to induce looping */ + n = tpl_node_new(parent); + n->type = TPL_TYPE_POUND; + n->num = pound_prod; + n->data = tpl_hook.malloc(sizeof(tpl_pound_data)); + if (!n->data) fatal_oom(); + pd = (tpl_pound_data*)n->data; + pd->inter_elt_len = inter_elt_len; + pd->iter_start_node = iter_start_node; + pd->iternum = 0; + DL_ADD(parent->children,n); + /* multiply the 'num' and data space on each atom in the structure */ + for(np = iter_start_node; np != n; np = np->next) { + if (n->parent->type == TPL_TYPE_ARY) { + ((tpl_atyp*)(n->parent->data))->sz += + tpl_types[np->type].sz * (np->num * (n->num - 1)); + } + np->data = tpl_hook.realloc(np->data, tpl_types[np->type].sz * + np->num * n->num); + if (!np->data) fatal_oom(); + memset(np->data, 0, tpl_types[np->type].sz * np->num * n->num); + } + } else { /* simple atom-# form does not require a loop */ + preceding->num = pound_prod; + preceding->data = tpl_hook.realloc(preceding->data, + tpl_types[t].sz * preceding->num); + if (!preceding->data) fatal_oom(); + memset(preceding->data,0,tpl_types[t].sz * preceding->num); + if (n->parent->type == TPL_TYPE_ARY) { + ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz * + (preceding->num-1); + } + } + root->ser_osz += (sizeof(uint32_t) * num_contig_fxlens); + + j = ((tpl_root_data*)root->data)->num_fxlens; /* before incrementing */ + (((tpl_root_data*)root->data)->num_fxlens) += num_contig_fxlens; + num_fxlens = ((tpl_root_data*)root->data)->num_fxlens; /* new value */ + fxlens = ((tpl_root_data*)root->data)->fxlens; + fxlens = tpl_hook.realloc(fxlens, sizeof(int) * num_fxlens); + if (!fxlens) fatal_oom(); + ((tpl_root_data*)root->data)->fxlens = fxlens; + for(i=0; i < num_contig_fxlens; i++) fxlens[j++] = contig_fxlens[i]; + + break; + case 'B': + if (expect_lparen) goto fail; + if (in_structure) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_BIN; + n->addr = (tpl_bin*)va_arg(ap,void*); + n->data = tpl_hook.malloc(sizeof(tpl_bin*)); + if (!n->data) fatal_oom(); + *((tpl_bin**)n->data) = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(tpl_bin); + DL_ADD(parent->children,n); + break; + case 'A': + if (in_structure) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_ARY; + DL_ADD(parent->children,n); + parent = n; + expect_lparen=1; + pidx = (tpl_pidx*)tpl_hook.malloc(sizeof(tpl_pidx)); + if (!pidx) fatal_oom(); + pidx->node = n; + pidx->next = NULL; + DL_ADD(((tpl_root_data*)(root->data))->pidx,pidx); + /* set up the A's tpl_atyp */ + n->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp)); + if (!n->data) fatal_oom(); + ((tpl_atyp*)(n->data))->num = 0; + ((tpl_atyp*)(n->data))->sz = 0; + ((tpl_atyp*)(n->data))->bb = NULL; + ((tpl_atyp*)(n->data))->bbtail = NULL; + ((tpl_atyp*)(n->data))->cur = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*); + break; + case 'S': + if (in_structure) goto fail; + expect_lparen=1; + ordinal=1; /* index upcoming atoms in S(..) */ + in_structure=1+lparen_level; /* so we can tell where S fmt ends */ + struct_addr = (char*)va_arg(ap,void*); + break; + case '$': /* nested structure */ + if (!in_structure) goto fail; + expect_lparen=1; + in_nested_structure++; + break; + case ')': + lparen_level--; + if (lparen_level < 0) goto fail; + if (*(c-1) == '(') goto fail; + if (in_nested_structure) in_nested_structure--; + else if (in_structure && (in_structure-1 == lparen_level)) { + /* calculate delta between contiguous structures in array */ + struct_next = calc_field_addr(parent, struct_widest_node->type, + struct_addr, ordinal++); + inter_elt_len = struct_next - struct_addr; + in_structure=0; + } + else parent = parent->parent; /* rparen ends A() type, not S() type */ + break; + case '(': + if (!expect_lparen) goto fail; + expect_lparen=0; + lparen_level++; + break; + default: + tpl_hook.oops("unsupported option %c\n", *c); + goto fail; + } + c++; + } + if (lparen_level != 0) goto fail; + + /* copy the format string, save for convenience */ + ((tpl_root_data*)(root->data))->fmt = tpl_hook.malloc(strlen(fmt)+1); + if (((tpl_root_data*)(root->data))->fmt == NULL) + fatal_oom(); + memcpy(((tpl_root_data*)(root->data))->fmt,fmt,strlen(fmt)+1); + + return root; + +fail: + tpl_hook.oops("failed to parse %s\n", fmt); + tpl_free(root); + return NULL; +} + +static int tpl_unmap_file( tpl_mmap_rec *mr) { + + if ( munmap( mr->text, mr->text_sz ) == -1 ) { + tpl_hook.oops("Failed to munmap: %s\n", strerror(errno)); + } + close(mr->fd); + mr->text = NULL; + mr->text_sz = 0; + return 0; +} + +static void tpl_free_keep_map(tpl_node *r) { + int mmap_bits = (TPL_RDONLY|TPL_FILE); + int ufree_bits = (TPL_MEM|TPL_UFREE); + tpl_node *nxtc,*c; + int find_next_node=0,looking,i; + size_t sz; + + /* For mmap'd files, or for 'ufree' memory images , do appropriate release */ + if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) { + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap); + } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) { + tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text ); + } + + c = r->children; + if (c) { + while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */ + switch (c->type) { + case TPL_TYPE_BIN: + /* free any binary buffer hanging from tpl_bin */ + if ( *((tpl_bin**)(c->data)) ) { + if ( (*((tpl_bin**)(c->data)))->addr ) { + tpl_hook.free( (*((tpl_bin**)(c->data)))->addr ); + } + *((tpl_bin**)c->data) = NULL; /* reset tpl_bin */ + } + find_next_node=1; + break; + case TPL_TYPE_STR: + /* free any packed (copied) string */ + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + if (str) { + tpl_hook.free(str); + ((char**)c->data)[i] = NULL; + } + } + find_next_node=1; + break; + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + case TPL_TYPE_POUND: + find_next_node=1; + break; + case TPL_TYPE_ARY: + c->ser_osz = 0; /* zero out the serialization output size */ + + sz = ((tpl_atyp*)(c->data))->sz; /* save sz to use below */ + tpl_free_atyp(c,c->data); + + /* make new atyp */ + c->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp)); + if (!c->data) fatal_oom(); + ((tpl_atyp*)(c->data))->num = 0; + ((tpl_atyp*)(c->data))->sz = sz; /* restore bb datum sz */ + ((tpl_atyp*)(c->data))->bb = NULL; + ((tpl_atyp*)(c->data))->bbtail = NULL; + ((tpl_atyp*)(c->data))->cur = NULL; + + c = c->children; + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + if (find_next_node) { + find_next_node=0; + looking=1; + while(looking) { + if (c->next) { + nxtc=c->next; + c=nxtc; + looking=0; + } else { + if (c->type == TPL_TYPE_ROOT) break; /* root node */ + else { + nxtc=c->parent; + c=nxtc; + } + } + } + } + } + } + + ((tpl_root_data*)(r->data))->flags = 0; /* reset flags */ +} + +TPL_API void tpl_free(tpl_node *r) { + int mmap_bits = (TPL_RDONLY|TPL_FILE); + int ufree_bits = (TPL_MEM|TPL_UFREE); + tpl_node *nxtc,*c; + int find_next_node=0,looking,i; + tpl_pidx *pidx,*pidx_nxt; + + /* For mmap'd files, or for 'ufree' memory images , do appropriate release */ + if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) { + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap); + } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) { + tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text ); + } + + c = r->children; + if (c) { + while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */ + switch (c->type) { + case TPL_TYPE_BIN: + /* free any binary buffer hanging from tpl_bin */ + if ( *((tpl_bin**)(c->data)) ) { + if ( (*((tpl_bin**)(c->data)))->sz != 0 ) { + tpl_hook.free( (*((tpl_bin**)(c->data)))->addr ); + } + tpl_hook.free(*((tpl_bin**)c->data)); /* free tpl_bin */ + } + tpl_hook.free(c->data); /* free tpl_bin* */ + find_next_node=1; + break; + case TPL_TYPE_STR: + /* free any packed (copied) string */ + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + if (str) { + tpl_hook.free(str); + ((char**)c->data)[i] = NULL; + } + } + tpl_hook.free(c->data); + find_next_node=1; + break; + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + case TPL_TYPE_POUND: + tpl_hook.free(c->data); + find_next_node=1; + break; + case TPL_TYPE_ARY: + tpl_free_atyp(c,c->data); + if (c->children) c = c->children; /* normal case */ + else find_next_node=1; /* edge case, handle bad format A() */ + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + if (find_next_node) { + find_next_node=0; + looking=1; + while(looking) { + if (c->next) { + nxtc=c->next; + tpl_hook.free(c); + c=nxtc; + looking=0; + } else { + if (c->type == TPL_TYPE_ROOT) break; /* root node */ + else { + nxtc=c->parent; + tpl_hook.free(c); + c=nxtc; + } + } + } + } + } + } + + /* free root */ + for(pidx=((tpl_root_data*)(r->data))->pidx; pidx; pidx=pidx_nxt) { + pidx_nxt = pidx->next; + tpl_hook.free(pidx); + } + tpl_hook.free(((tpl_root_data*)(r->data))->fmt); + if (((tpl_root_data*)(r->data))->num_fxlens > 0) { + tpl_hook.free(((tpl_root_data*)(r->data))->fxlens); + } + tpl_hook.free(r->data); /* tpl_root_data */ + tpl_hook.free(r); +} + + +/* Find the i'th packable ('A' node) */ +static tpl_node *tpl_find_i(tpl_node *n, int i) { + int j=0; + tpl_pidx *pidx; + if (n->type != TPL_TYPE_ROOT) return NULL; + if (i == 0) return n; /* packable 0 is root */ + for(pidx=((tpl_root_data*)(n->data))->pidx; pidx; pidx=pidx->next) { + if (++j == i) return pidx->node; + } + return NULL; +} + +static void *tpl_cpv(void *datav, void *data, size_t sz) { + if (sz>0) memcpy(datav,data,sz); + return (void*)((uintptr_t)datav + sz); +} + +static void *tpl_extend_backbone(tpl_node *n) { + tpl_backbone *bb; + bb = (tpl_backbone*)tpl_hook.malloc(sizeof(tpl_backbone) + + ((tpl_atyp*)(n->data))->sz ); /* datum hangs on coattails of bb */ + if (!bb) fatal_oom(); +#if __STDC_VERSION__ < 199901 + bb->data = (char*)((uintptr_t)bb + sizeof(tpl_backbone)); +#endif + memset(bb->data,0,((tpl_atyp*)(n->data))->sz); + bb->next = NULL; + /* Add the new backbone to the tail, also setting head if necessary */ + if (((tpl_atyp*)(n->data))->bb == NULL) { + ((tpl_atyp*)(n->data))->bb = bb; + ((tpl_atyp*)(n->data))->bbtail = bb; + } else { + ((tpl_atyp*)(n->data))->bbtail->next = bb; + ((tpl_atyp*)(n->data))->bbtail = bb; + } + + ((tpl_atyp*)(n->data))->num++; + return bb->data; +} + +/* Get the format string corresponding to a given tpl (root node) */ +static char *tpl_fmt(tpl_node *r) { + return ((tpl_root_data*)(r->data))->fmt; +} + +/* Get the fmt # lengths as a contiguous buffer of ints (length num_fxlens) */ +static int *tpl_fxlens(tpl_node *r, int *num_fxlens) { + *num_fxlens = ((tpl_root_data*)(r->data))->num_fxlens; + return ((tpl_root_data*)(r->data))->fxlens; +} + +/* called when serializing an 'A' type node into a buffer which has + * already been set up with the proper space. The backbone is walked + * which was obtained from the tpl_atyp header passed in. + */ +static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv) { + tpl_backbone *bb; + tpl_node *c; + void *datav; + uint32_t slen; + tpl_bin *binp; + char *strp; + tpl_atyp *atypp; + tpl_pound_data *pd; + int i; + size_t itermax; + + /* handle 'A' nodes */ + dv = tpl_cpv(dv,&at->num,sizeof(uint32_t)); /* array len */ + for(bb=at->bb; bb; bb=bb->next) { + datav = bb->data; + c=n->children; + while(c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = tpl_cpv(dv,datav,tpl_types[c->type].sz * c->num); + datav = (void*)((uintptr_t)datav + tpl_types[c->type].sz * c->num); + break; + case TPL_TYPE_BIN: + /* dump the buffer length followed by the buffer */ + memcpy(&binp,datav,sizeof(tpl_bin*)); /* cp to aligned */ + slen = binp->sz; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); + dv = tpl_cpv(dv,binp->addr,slen); + datav = (void*)((uintptr_t)datav + sizeof(tpl_bin*)); + break; + case TPL_TYPE_STR: + /* dump the string length followed by the string */ + for(i=0; i < c->num; i++) { + memcpy(&strp,datav,sizeof(char*)); /* cp to aligned */ + slen = strp ? (strlen(strp)+1) : 0; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); + if (slen > 1) dv = tpl_cpv(dv,strp,slen-1); + datav = (void*)((uintptr_t)datav + sizeof(char*)); + } + break; + case TPL_TYPE_ARY: + memcpy(&atypp,datav,sizeof(tpl_atyp*)); /* cp to aligned */ + dv = tpl_dump_atyp(c,atypp,dv); + datav = (void*)((uintptr_t)datav + sizeof(void*)); + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + } + return dv; +} + +/* figure the serialization output size needed for tpl whose root is n*/ +static size_t tpl_ser_osz(tpl_node *n) { + tpl_node *c, *np; + size_t sz, itermax; + tpl_bin *binp; + char *strp; + tpl_pound_data *pd; + int i; + + /* handle the root node ONLY (subtree's ser_osz have been bubbled-up) */ + if (n->type != TPL_TYPE_ROOT) { + tpl_hook.fatal("internal error: tpl_ser_osz on non-root node\n"); + } + + sz = n->ser_osz; /* start with fixed overhead, already stored */ + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + sz += tpl_types[c->type].sz * c->num; + break; + case TPL_TYPE_BIN: + sz += sizeof(uint32_t); /* binary buf len */ + memcpy(&binp,c->data,sizeof(tpl_bin*)); /* cp to aligned */ + sz += binp->sz; + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + sz += sizeof(uint32_t); /* string len */ + memcpy(&strp,&((char**)c->data)[i],sizeof(char*)); /* cp to aligned */ + sz += strp ? strlen(strp) : 0; + } + break; + case TPL_TYPE_ARY: + sz += sizeof(uint32_t); /* array len */ + sz += c->ser_osz; /* bubbled-up child array ser_osz */ + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + } + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + } + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + return sz; +} + + +TPL_API int tpl_dump(tpl_node *r, int mode, ...) { + va_list ap; + char *filename, *bufv; + void **addr_out,*buf, *pa_addr; + int fd,rc=0; + size_t sz,*sz_out, pa_sz; + struct stat sbuf; + + if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) { /* unusual */ + tpl_hook.oops("error: tpl_dump called for a loaded tpl\n"); + return -1; + } + + sz = tpl_ser_osz(r); /* compute the size needed to serialize */ + + va_start(ap,mode); + if (mode & TPL_FILE) { + filename = va_arg(ap,char*); + fd = tpl_mmap_output_file(filename, sz, &buf); + if (fd == -1) rc = -1; + else { + rc = tpl_dump_to_mem(r,buf,sz); + if (msync(buf,sz,MS_SYNC) == -1) { + tpl_hook.oops("msync failed on fd %d: %s\n", fd, strerror(errno)); + } + if (munmap(buf, sz) == -1) { + tpl_hook.oops("munmap failed on fd %d: %s\n", fd, strerror(errno)); + } + close(fd); + } + } else if (mode & TPL_FD) { + fd = va_arg(ap, int); + if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom(); + tpl_dump_to_mem(r,buf,sz); + bufv = buf; + do { + rc = write(fd,bufv,sz); + if (rc > 0) { + sz -= rc; + bufv += rc; + } else if (rc == -1) { + if (errno == EINTR || errno == EAGAIN) continue; + tpl_hook.oops("error writing to fd %d: %s\n", fd, strerror(errno)); + free(buf); + /* attempt to rewind partial write to a regular file */ + if (fstat(fd, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) { + if (ftruncate(fd, sbuf.st_size - (bufv-(char*)buf)) == -1) { + tpl_hook.oops("can't rewind: %s\n", strerror(errno)); + } + } + return -1; + } + } while (sz > 0); + free(buf); + rc = 0; + } else if (mode & TPL_MEM) { + if (mode & TPL_PREALLOCD) { /* caller allocated */ + pa_addr = (void*)va_arg(ap, void*); + pa_sz = va_arg(ap, size_t); + if (pa_sz < sz) { + tpl_hook.oops("tpl_dump: buffer too small, need %d bytes\n", sz); + return -1; + } + rc=tpl_dump_to_mem(r,pa_addr,sz); + } else { /* we allocate */ + addr_out = (void**)va_arg(ap, void*); + sz_out = va_arg(ap, size_t*); + if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom(); + *sz_out = sz; + *addr_out = buf; + rc=tpl_dump_to_mem(r,buf,sz); + } + } else if (mode & TPL_GETSIZE) { + sz_out = va_arg(ap, size_t*); + *sz_out = sz; + } else { + tpl_hook.oops("unsupported tpl_dump mode %d\n", mode); + rc=-1; + } + va_end(ap); + return rc; +} + +/* This function expects the caller to have set up a memory buffer of + * adequate size to hold the serialized tpl. The sz parameter must be + * the result of tpl_ser_osz(r). + */ +static int tpl_dump_to_mem(tpl_node *r,void *addr,size_t sz) { + uint32_t slen, sz32; + int *fxlens, num_fxlens, i; + void *dv; + char *fmt,flags; + tpl_node *c, *np; + tpl_pound_data *pd; + size_t itermax; + + fmt = tpl_fmt(r); + flags = 0; + if (tpl_cpu_bigendian()) flags |= TPL_FL_BIGENDIAN; + if (strchr(fmt,'s')) flags |= TPL_FL_NULLSTRINGS; + sz32 = sz; + + dv = addr; + dv = tpl_cpv(dv,TPL_MAGIC,3); /* copy tpl magic prefix */ + dv = tpl_cpv(dv,&flags,1); /* copy flags byte */ + dv = tpl_cpv(dv,&sz32,sizeof(uint32_t));/* overall length (inclusive) */ + dv = tpl_cpv(dv,fmt,strlen(fmt)+1); /* copy format with NUL-term */ + fxlens = tpl_fxlens(r,&num_fxlens); + dv = tpl_cpv(dv,fxlens,num_fxlens*sizeof(uint32_t));/* fmt # lengths */ + + /* serialize the tpl content, iterating over direct children of root */ + c = r->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = tpl_cpv(dv,c->data,tpl_types[c->type].sz * c->num); + break; + case TPL_TYPE_BIN: + slen = (*(tpl_bin**)(c->data))->sz; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* buffer len */ + dv = tpl_cpv(dv,(*(tpl_bin**)(c->data))->addr,slen); /* buf */ + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + slen = str ? strlen(str)+1 : 0; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* string len */ + if (slen>1) dv = tpl_cpv(dv,str,slen-1); /*string*/ + } + break; + case TPL_TYPE_ARY: + dv = tpl_dump_atyp(c,(tpl_atyp*)c->data,dv); + break; + case TPL_TYPE_POUND: + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + + /* in start or midst of loop. advance data pointers. */ + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + } + /* do next iteration */ + c = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + } + + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c = c->next; + } + + return 0; +} + +static int tpl_cpu_bigendian() { + unsigned i = 1; + char *c; + c = (char*)&i; + return (c[0] == 1 ? 0 : 1); +} + + +/* + * algorithm for sanity-checking a tpl image: + * scan the tpl whilst not exceeding the buffer size (bufsz) , + * formulating a calculated (expected) size of the tpl based + * on walking its data. When calcsize has been calculated it + * should exactly match the buffer size (bufsz) and the internal + * recorded size (intlsz) + */ +static int tpl_sanity(tpl_node *r, int excess_ok) { + uint32_t intlsz; + int found_nul=0,rc, octothorpes=0, num_fxlens, *fxlens, flen; + void *d, *dv; + char intlflags, *fmt, c, *mapfmt; + size_t bufsz, serlen; + + d = ((tpl_root_data*)(r->data))->mmap.text; + bufsz = ((tpl_root_data*)(r->data))->mmap.text_sz; + + dv = d; + if (bufsz < (4 + sizeof(uint32_t) + 1)) return ERR_NOT_MINSIZE; /* min sz: magic+flags+len+nul */ + if (memcmp(dv,TPL_MAGIC, 3) != 0) return ERR_MAGIC_MISMATCH; /* missing tpl magic prefix */ + if (tpl_needs_endian_swap(dv)) ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN; + dv = (void*)((uintptr_t)dv + 3); + memcpy(&intlflags,dv,sizeof(char)); /* extract flags */ + if (intlflags & ~TPL_SUPPORTED_BITFLAGS) return ERR_UNSUPPORTED_FLAGS; + /* TPL1.3 stores strings with a "length+1" prefix to discern NULL strings from + empty strings from non-empty strings; TPL1.2 only handled the latter two. + So we need to be mindful of which string format we're reading from. */ + if (!(intlflags & TPL_FL_NULLSTRINGS)) { + ((tpl_root_data*)(r->data))->flags |= TPL_OLD_STRING_FMT; + } + dv = (void*)((uintptr_t)dv + 1); + memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&intlsz, sizeof(uint32_t)); + if (!excess_ok && (intlsz != bufsz)) return ERR_INCONSISTENT_SZ; /* inconsisent buffer/internal size */ + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + + /* dv points to the start of the format string. Look for nul w/in buf sz */ + fmt = (char*)dv; + while ((uintptr_t)dv-(uintptr_t)d < bufsz && !found_nul) { + if ( (c = *(char*)dv) != '\0') { + if (strchr(tpl_fmt_chars,c) == NULL) + return ERR_FMT_INVALID; /* invalid char in format string */ + if ( (c = *(char*)dv) == '#') octothorpes++; + dv = (void*)((uintptr_t)dv + 1); + } + else found_nul = 1; + } + if (!found_nul) return ERR_FMT_MISSING_NUL; /* runaway format string */ + dv = (void*)((uintptr_t)dv + 1); /* advance to octothorpe lengths buffer */ + + /* compare the map format to the format of this tpl image */ + mapfmt = tpl_fmt(r); + rc = strcmp(mapfmt,fmt); + if (rc != 0) return ERR_FMT_MISMATCH; + + /* compare octothorpe lengths in image to the mapped values */ + if ((((uintptr_t)dv + (octothorpes * 4)) - (uintptr_t)d) > bufsz) return ERR_INCONSISTENT_SZ4; + fxlens = tpl_fxlens(r,&num_fxlens); /* mapped fxlens */ + while(num_fxlens--) { + memcpy(&flen,dv,sizeof(uint32_t)); /* stored flen */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&flen, sizeof(uint32_t)); + if (flen != *fxlens) return ERR_FLEN_MISMATCH; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + fxlens++; + } + + /* dv now points to beginning of data */ + rc = tpl_serlen(r,r,dv,&serlen); /* get computed serlen of data part */ + if (rc == -1) return ERR_INCONSISTENT_SZ2; /* internal inconsistency in tpl image */ + serlen += ((uintptr_t)dv - (uintptr_t)d); /* add back serlen of preamble part */ + if (excess_ok && (bufsz < serlen)) return ERR_INCONSISTENT_SZ3; + if (!excess_ok && (serlen != bufsz)) return ERR_INCONSISTENT_SZ3; /* buffer/internal sz exceeds serlen */ + return 0; +} + +static void *tpl_find_data_start(void *d) { + int octothorpes=0; + d = (void*)((uintptr_t)d + 4); /* skip TPL_MAGIC and flags byte */ + d = (void*)((uintptr_t)d + 4); /* skip int32 overall len */ + while(*(char*)d != '\0') { + if (*(char*)d == '#') octothorpes++; + d = (void*)((uintptr_t)d + 1); + } + d = (void*)((uintptr_t)d + 1); /* skip NUL */ + d = (void*)((uintptr_t)d + (octothorpes * sizeof(uint32_t))); /* skip # array lens */ + return d; +} + +static int tpl_needs_endian_swap(void *d) { + char *c; + int cpu_is_bigendian; + c = (char*)d; + cpu_is_bigendian = tpl_cpu_bigendian(); + return ((c[3] & TPL_FL_BIGENDIAN) == cpu_is_bigendian) ? 0 : 1; +} + +static size_t tpl_size_for(char c) { + int i; + for(i=0; i < sizeof(tpl_types)/sizeof(tpl_types[0]); i++) { + if (tpl_types[i].c == c) return tpl_types[i].sz; + } + return 0; +} + +TPL_API char* tpl_peek(int mode, ...) { + va_list ap; + int xendian=0,found_nul=0,old_string_format=0; + char *filename=NULL, *datapeek_f=NULL, *datapeek_c, *datapeek_s; + void *addr=NULL, *dv, *datapeek_p=NULL; + size_t sz=0, fmt_len, first_atom, num_fxlens=0; + uint32_t datapeek_ssz, datapeek_csz, datapeek_flen; + tpl_mmap_rec mr = {0,NULL,0}; + char *fmt,*fmt_cpy=NULL,c; + uint32_t intlsz, **fxlens=NULL, *num_fxlens_out=NULL, *fxlensv; + + va_start(ap,mode); + if ((mode & TPL_FXLENS) && (mode & TPL_DATAPEEK)) { + tpl_hook.oops("TPL_FXLENS and TPL_DATAPEEK mutually exclusive\n"); + goto fail; + } + if (mode & TPL_FILE) filename = va_arg(ap,char *); + else if (mode & TPL_MEM) { + addr = va_arg(ap,void *); + sz = va_arg(ap,size_t); + } else { + tpl_hook.oops("unsupported tpl_peek mode %d\n", mode); + goto fail; + } + if (mode & TPL_DATAPEEK) { + datapeek_f = va_arg(ap, char*); + } + if (mode & TPL_FXLENS) { + num_fxlens_out = va_arg(ap,uint32_t *); + fxlens = va_arg(ap,uint32_t **); + *num_fxlens_out = 0; + *fxlens = NULL; + } + + if (mode & TPL_FILE) { + if (tpl_mmap_file(filename, &mr) != 0) { + tpl_hook.oops("tpl_peek failed for file %s\n", filename); + goto fail; + } + addr = mr.text; + sz = mr.text_sz; + } + + dv = addr; + if (sz < (4 + sizeof(uint32_t) + 1)) goto fail; /* min sz */ + if (memcmp(dv,TPL_MAGIC, 3) != 0) goto fail; /* missing tpl magic prefix */ + if (tpl_needs_endian_swap(dv)) xendian=1; + if ((((char*)dv)[3] & TPL_FL_NULLSTRINGS)==0) old_string_format=1; + dv = (void*)((uintptr_t)dv + 4); + memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */ + if (xendian) tpl_byteswap(&intlsz, sizeof(uint32_t)); + if (intlsz != sz) goto fail; /* inconsisent buffer/internal size */ + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + + /* dv points to the start of the format string. Look for nul w/in buf sz */ + fmt = (char*)dv; + while ((uintptr_t)dv-(uintptr_t)addr < sz && !found_nul) { + if ( (c = *(char*)dv) == '\0') { + found_nul = 1; + } else if (c == '#') { + num_fxlens++; + } + dv = (void*)((uintptr_t)dv + 1); + } + if (!found_nul) goto fail; /* runaway format string */ + fmt_len = (char*)dv - fmt; /* include space for \0 */ + fmt_cpy = tpl_hook.malloc(fmt_len); + if (fmt_cpy == NULL) { + fatal_oom(); + } + memcpy(fmt_cpy, fmt, fmt_len); + + /* retrieve the octothorpic lengths if requested */ + if (num_fxlens > 0) { + if (sz < ((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)) - (uintptr_t)addr)) { + goto fail; + } + } + if ((mode & TPL_FXLENS) && (num_fxlens > 0)) { + *fxlens = tpl_hook.malloc(num_fxlens * sizeof(uint32_t)); + if (*fxlens == NULL) tpl_hook.fatal("out of memory"); + *num_fxlens_out = num_fxlens; + fxlensv = *fxlens; + while(num_fxlens--) { + memcpy(fxlensv,dv,sizeof(uint32_t)); + if (xendian) tpl_byteswap(fxlensv, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + fxlensv++; + } + } + /* if caller requested, peek into the specified data elements */ + if (mode & TPL_DATAPEEK) { + + first_atom = strspn(fmt, "S()"); /* skip any leading S() */ + + datapeek_flen = strlen(datapeek_f); + if (strspn(datapeek_f, tpl_datapeek_ok_chars) < datapeek_flen) { + tpl_hook.oops("invalid TPL_DATAPEEK format: %s\n", datapeek_f); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + + if (strncmp( &fmt[first_atom], datapeek_f, datapeek_flen) != 0) { + //tpl_hook.oops("TPL_DATAPEEK format mismatches tpl iamge\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + + /* advance to data start, then copy out requested elements */ + dv = (void*)((uintptr_t)dv + (num_fxlens * sizeof(uint32_t))); + for(datapeek_c = datapeek_f; *datapeek_c != '\0'; datapeek_c++) { + datapeek_p = va_arg(ap, void*); + if (*datapeek_c == 's') { /* special handling for strings */ + if ((uintptr_t)dv-(uintptr_t)addr + sizeof(uint32_t) > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + memcpy(&datapeek_ssz,dv,sizeof(uint32_t)); /* get slen */ + if (xendian) tpl_byteswap(&datapeek_ssz, sizeof(uint32_t)); + if (old_string_format) datapeek_ssz++; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); /* adv. to str */ + if (datapeek_ssz == 0) datapeek_s = NULL; + else { + if ((uintptr_t)dv-(uintptr_t)addr + datapeek_ssz-1 > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + datapeek_s = tpl_hook.malloc(datapeek_ssz); + if (datapeek_s == NULL) fatal_oom(); + memcpy(datapeek_s, dv, datapeek_ssz-1); + datapeek_s[datapeek_ssz-1] = '\0'; + dv = (void*)((uintptr_t)dv + datapeek_ssz-1); + } + *(char**)datapeek_p = datapeek_s; + } else { + datapeek_csz = tpl_size_for(*datapeek_c); + if ((uintptr_t)dv-(uintptr_t)addr + datapeek_csz > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + memcpy(datapeek_p, dv, datapeek_csz); + if (xendian) tpl_byteswap(datapeek_p, datapeek_csz); + dv = (void*)((uintptr_t)dv + datapeek_csz); + } + } + } + +fail: + va_end(ap); + if ((mode & TPL_FILE) && mr.text != NULL) tpl_unmap_file( &mr ); + return fmt_cpy; +} + +/* tpl_jot(TPL_FILE, "file.tpl", "si", &s, &i); */ +/* tpl_jot(TPL_MEM, &buf, &sz, "si", &s, &i); */ +/* tpl_jot(TPL_FD, fd, "si", &s, &i); */ +TPL_API int tpl_jot(int mode, ...) { + va_list ap; + char *filename, *fmt; + size_t *sz; + int fd, rc=0; + void **buf; + tpl_node *tn; + + va_start(ap,mode); + if (mode & TPL_FILE) { + filename = va_arg(ap,char*); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt, ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn, 0); + rc = tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + } else if (mode & TPL_MEM) { + buf = va_arg(ap,void*); + sz = va_arg(ap,size_t*); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt,ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn,0); + rc = tpl_dump(tn, TPL_MEM, buf, sz); + tpl_free(tn); + } else if (mode & TPL_FD) { + fd = va_arg(ap,int); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt,ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn,0); + rc = tpl_dump(tn, TPL_FD, fd); + tpl_free(tn); + } else { + tpl_hook.fatal("invalid tpl_jot mode\n"); + } + +fail: + va_end(ap); + return rc; +} + +TPL_API int tpl_load(tpl_node *r, int mode, ...) { + va_list ap; + int rc=0,fd=0; + char *filename=NULL; + void *addr; + size_t sz; + + va_start(ap,mode); + if (mode & TPL_FILE) filename = va_arg(ap,char *); + else if (mode & TPL_MEM) { + addr = va_arg(ap,void *); + sz = va_arg(ap,size_t); + } else if (mode & TPL_FD) { + fd = va_arg(ap,int); + } else { + tpl_hook.oops("unsupported tpl_load mode %d\n", mode); + return -1; + } + va_end(ap); + + if (r->type != TPL_TYPE_ROOT) { + tpl_hook.oops("error: tpl_load to non-root node\n"); + return -1; + } + if (((tpl_root_data*)(r->data))->flags & (TPL_WRONLY|TPL_RDONLY)) { + /* already packed or loaded, so reset it as if newly mapped */ + tpl_free_keep_map(r); + } + if (mode & TPL_FILE) { + if (tpl_mmap_file(filename, &((tpl_root_data*)(r->data))->mmap) != 0) { + tpl_hook.oops("tpl_load failed for file %s\n", filename); + return -1; + } + if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) { + if (rc == ERR_FMT_MISMATCH) { + tpl_hook.oops("%s: format signature mismatch\n", filename); + } else if (rc == ERR_FLEN_MISMATCH) { + tpl_hook.oops("%s: array lengths mismatch\n", filename); + } else { + tpl_hook.oops("%s: not a valid tpl file\n", filename); + } + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap ); + return -1; + } + ((tpl_root_data*)(r->data))->flags = (TPL_FILE | TPL_RDONLY); + } else if (mode & TPL_MEM) { + ((tpl_root_data*)(r->data))->mmap.text = addr; + ((tpl_root_data*)(r->data))->mmap.text_sz = sz; + if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) { + if (rc == ERR_FMT_MISMATCH) { + tpl_hook.oops("format signature mismatch\n"); + } else { + tpl_hook.oops("not a valid tpl file\n"); + } + return -1; + } + ((tpl_root_data*)(r->data))->flags = (TPL_MEM | TPL_RDONLY); + if (mode & TPL_UFREE) ((tpl_root_data*)(r->data))->flags |= TPL_UFREE; + } else if (mode & TPL_FD) { + /* if fd read succeeds, resulting mem img is used for load */ + if (tpl_gather(TPL_GATHER_BLOCKING,fd,&addr,&sz) > 0) { + return tpl_load(r, TPL_MEM|TPL_UFREE, addr, sz); + } else return -1; + } else { + tpl_hook.oops("invalid tpl_load mode %d\n", mode); + return -1; + } + /* this applies to TPL_MEM or TPL_FILE */ + if (tpl_needs_endian_swap(((tpl_root_data*)(r->data))->mmap.text)) + ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN; + tpl_unpackA0(r); /* prepare root A nodes for use */ + return 0; +} + +TPL_API int tpl_Alen(tpl_node *r, int i) { + tpl_node *n; + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_unpack\n", i); + return -1; + } + if (n->type != TPL_TYPE_ARY) return -1; + return ((tpl_atyp*)(n->data))->num; +} + +static void tpl_free_atyp(tpl_node *n, tpl_atyp *atyp) { + tpl_backbone *bb,*bbnxt; + tpl_node *c; + void *dv; + tpl_bin *binp; + tpl_atyp *atypp; + char *strp; + size_t itermax; + tpl_pound_data *pd; + int i; + + bb = atyp->bb; + while (bb) { + bbnxt = bb->next; + dv = bb->data; + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz*c->num); + break; + case TPL_TYPE_BIN: + memcpy(&binp,dv,sizeof(tpl_bin*)); /* cp to aligned */ + if (binp->addr) tpl_hook.free( binp->addr ); /* free buf */ + tpl_hook.free(binp); /* free tpl_bin */ + dv = (void*)((uintptr_t)dv + sizeof(tpl_bin*)); + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + memcpy(&strp,dv,sizeof(char*)); /* cp to aligned */ + if (strp) tpl_hook.free(strp); /* free string */ + dv = (void*)((uintptr_t)dv + sizeof(char*)); + } + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + case TPL_TYPE_ARY: + memcpy(&atypp,dv,sizeof(tpl_atyp*)); /* cp to aligned */ + tpl_free_atyp(c,atypp); /* free atyp */ + dv = (void*)((uintptr_t)dv + sizeof(void*)); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + tpl_hook.free(bb); + bb = bbnxt; + } + tpl_hook.free(atyp); +} + +/* determine (by walking) byte length of serialized r/A node at address dv + * returns 0 on success, or -1 if the tpl isn't trustworthy (fails consistency) + */ +static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen) { + uint32_t slen; + int num,fidx; + tpl_node *c; + size_t len=0, alen, buf_past, itermax; + tpl_pound_data *pd; + + buf_past = ((uintptr_t)((tpl_root_data*)(r->data))->mmap.text + + ((tpl_root_data*)(r->data))->mmap.text_sz); + + if (n->type == TPL_TYPE_ROOT) num = 1; + else if (n->type == TPL_TYPE_ARY) { + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&num,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&num, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + len += sizeof(uint32_t); + } else tpl_hook.fatal("internal error in tpl_serlen\n"); + + while (num-- > 0) { + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */ + if ((uintptr_t)dv + tpl_types[c->type].sz > buf_past) return -1; + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + len += tpl_types[c->type].sz; + } + break; + case TPL_TYPE_BIN: + len += sizeof(uint32_t); + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + len += slen; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if ((uintptr_t)dv + slen > buf_past) return -1; + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */ + len += sizeof(uint32_t); + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (!(((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT)) + slen = (slen>1) ? (slen-1) : 0; + len += slen; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if ((uintptr_t)dv + slen > buf_past) return -1; + dv = (void*)((uintptr_t)dv + slen); + } + break; + case TPL_TYPE_ARY: + if ( tpl_serlen(r,c,dv, &alen) == -1) return -1; + dv = (void*)((uintptr_t)dv + alen); + len += alen; + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + } + *serlen = len; + return 0; +} + +static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out) { + void *text; + int fd,perms; + +#ifndef _WIN32 + perms = S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH; /* ug+w o+r */ + fd=open(filename,O_CREAT|O_TRUNC|O_RDWR,perms); +#else + perms = _S_IWRITE; + fd=_open(filename,_O_CREAT|_O_TRUNC|_O_RDWR,perms); +#endif + + if ( fd == -1 ) { + tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno)); + return -1; + } + + text = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (text == MAP_FAILED) { + tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno)); + close(fd); + return -1; + } + if (ftruncate(fd,sz) == -1) { + tpl_hook.oops("ftruncate failed: %s\n", strerror(errno)); + munmap( text, sz ); + close(fd); + return -1; + } + *text_out = text; + return fd; +} + +static int tpl_mmap_file(char *filename, tpl_mmap_rec *mr) { + struct stat stat_buf; + + if ( (mr->fd = open(filename, O_RDONLY)) == -1 ) { + tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno)); + return -1; + } + + if ( fstat(mr->fd, &stat_buf) == -1) { + close(mr->fd); + tpl_hook.oops("Couldn't stat file %s: %s\n", filename, strerror(errno)); + return -1; + } + + mr->text_sz = (size_t)stat_buf.st_size; + mr->text = mmap(0, stat_buf.st_size, PROT_READ, MAP_PRIVATE, mr->fd, 0); + if (mr->text == MAP_FAILED) { + close(mr->fd); + tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno)); + return -1; + } + + return 0; +} + +TPL_API int tpl_pack(tpl_node *r, int i) { + tpl_node *n, *child, *np; + void *datav=NULL; + size_t sz, itermax; + uint32_t slen; + char *str; + tpl_bin *bin; + tpl_pound_data *pd; + int fidx; + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_pack\n", i); + return -1; + } + + if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) { + /* convert to an writeable tpl, initially empty */ + tpl_free_keep_map(r); + } + + ((tpl_root_data*)(r->data))->flags |= TPL_WRONLY; + + if (n->type == TPL_TYPE_ARY) datav = tpl_extend_backbone(n); + child = n->children; + while(child) { + switch(child->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + /* no need to use fidx iteration here; we can copy multiple values in one memcpy */ + memcpy(child->data,child->addr,tpl_types[child->type].sz * child->num); + if (datav) datav = tpl_cpv(datav,child->data,tpl_types[child->type].sz * child->num); + if (n->type == TPL_TYPE_ARY) n->ser_osz += tpl_types[child->type].sz * child->num; + break; + case TPL_TYPE_BIN: + /* copy the buffer to be packed */ + slen = ((tpl_bin*)child->addr)->sz; + if (slen >0) { + str = tpl_hook.malloc(slen); + if (!str) fatal_oom(); + memcpy(str,((tpl_bin*)child->addr)->addr,slen); + } else str = NULL; + /* and make a tpl_bin to point to it */ + bin = tpl_hook.malloc(sizeof(tpl_bin)); + if (!bin) fatal_oom(); + bin->addr = str; + bin->sz = slen; + /* now pack its pointer, first deep freeing any pre-existing bin */ + if (*(tpl_bin**)(child->data) != NULL) { + if ((*(tpl_bin**)(child->data))->sz != 0) { + tpl_hook.free( (*(tpl_bin**)(child->data))->addr ); + } + tpl_hook.free(*(tpl_bin**)(child->data)); + } + memcpy(child->data,&bin,sizeof(tpl_bin*)); + if (datav) { + datav = tpl_cpv(datav, &bin, sizeof(tpl_bin*)); + *(tpl_bin**)(child->data) = NULL; + } + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* binary buf len word */ + n->ser_osz += bin->sz; /* binary buf */ + } + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < child->num; fidx++) { + /* copy the string to be packed. slen includes \0. this + block also works if the string pointer is NULL. */ + char *caddr = ((char**)child->addr)[fidx]; + char **cdata = &((char**)child->data)[fidx]; + slen = caddr ? (strlen(caddr) + 1) : 0; + if (slen) { + str = tpl_hook.malloc(slen); + if (!str) fatal_oom(); + memcpy(str,caddr,slen); /* include \0 */ + } else { + str = NULL; + } + /* now pack its pointer, first freeing any pre-existing string */ + if (*cdata != NULL) { + tpl_hook.free(*cdata); + } + memcpy(cdata,&str,sizeof(char*)); + if (datav) { + datav = tpl_cpv(datav, &str, sizeof(char*)); + *cdata = NULL; + } + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* string len word */ + if (slen>1) n->ser_osz += slen-1;/* string (without nul) */ + } + } + break; + case TPL_TYPE_ARY: + /* copy the child's tpl_atype* and reset it to empty */ + if (datav) { + sz = ((tpl_atyp*)(child->data))->sz; + datav = tpl_cpv(datav, &child->data, sizeof(void*)); + child->data = tpl_hook.malloc(sizeof(tpl_atyp)); + if (!child->data) fatal_oom(); + ((tpl_atyp*)(child->data))->num = 0; + ((tpl_atyp*)(child->data))->sz = sz; + ((tpl_atyp*)(child->data))->bb = NULL; + ((tpl_atyp*)(child->data))->bbtail = NULL; + } + /* parent is array? then bubble up child array's ser_osz */ + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* array len word */ + n->ser_osz += child->ser_osz; /* child array ser_osz */ + child->ser_osz = 0; /* reset child array ser_osz */ + } + break; + + case TPL_TYPE_POUND: + /* we need to iterate n times over preceding nodes in S(...). + * we may be in the midst of an iteration each time or starting. */ + pd = (tpl_pound_data*)child->data; + itermax = child->num; + + /* itermax is total num of iterations needed */ + /* pd->iternum is current iteration index */ + /* pd->inter_elt_len is element-to-element len of contiguous structs */ + /* pd->iter_start_node is where we jump to at each iteration. */ + + if (++(pd->iternum) < itermax) { + + /* in start or midst of loop. advance addr/data pointers. */ + for(np=pd->iter_start_node; np != child; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + np->addr = (char*)(np->addr) + pd->inter_elt_len; + } + /* do next iteration */ + child = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != child; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len); + } + + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + child=child->next; + } + return 0; +} + +TPL_API int tpl_unpack(tpl_node *r, int i) { + tpl_node *n, *c, *np; + uint32_t slen; + int rc=1, fidx; + char *str; + void *dv=NULL, *caddr; + size_t A_bytes, itermax; + tpl_pound_data *pd; + void *img; + size_t sz; + + + /* handle unusual case of tpl_pack,tpl_unpack without an + * intervening tpl_dump. do a dump/load implicitly. */ + if (((tpl_root_data*)(r->data))->flags & TPL_WRONLY) { + if (tpl_dump(r,TPL_MEM,&img,&sz) != 0) return -1; + if (tpl_load(r,TPL_MEM|TPL_UFREE,img,sz) != 0) { + tpl_hook.free(img); + return -1; + }; + } + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_unpack\n", i); + return -1; + } + + /* either root node or an A node */ + if (n->type == TPL_TYPE_ROOT) { + dv = tpl_find_data_start( ((tpl_root_data*)(n->data))->mmap.text ); + } else if (n->type == TPL_TYPE_ARY) { + if (((tpl_atyp*)(n->data))->num <= 0) return 0; /* array consumed */ + else rc = ((tpl_atyp*)(n->data))->num--; + dv = ((tpl_atyp*)(n->data))->cur; + if (!dv) tpl_hook.fatal("must unpack parent of node before node itself\n"); + } + + c = n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + /* unpack elements of cross-endian octothorpic array individually */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) { + for(fidx=0; fidx < c->num; fidx++) { + caddr = (void*)((uintptr_t)c->addr + (fidx * tpl_types[c->type].sz)); + memcpy(caddr,dv,tpl_types[c->type].sz); + tpl_byteswap(caddr, tpl_types[c->type].sz); + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + } + } else { + /* bulk unpack ok if not cross-endian */ + memcpy(c->addr, dv, tpl_types[c->type].sz * c->num); + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz * c->num); + } + break; + case TPL_TYPE_BIN: + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (slen > 0) { + str = (char*)tpl_hook.malloc(slen); + if (!str) fatal_oom(); + } else str=NULL; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen>0) memcpy(str,dv,slen); + memcpy(&(((tpl_bin*)c->addr)->addr),&str,sizeof(void*)); + memcpy(&(((tpl_bin*)c->addr)->sz),&slen,sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < c->num; fidx++) { + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT) + slen += 1; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen) { /* slen includes \0 */ + str = (char*)tpl_hook.malloc(slen); + if (!str) fatal_oom(); + if (slen>1) memcpy(str,dv,slen-1); + str[slen-1] = '\0'; /* nul terminate */ + dv = (void*)((uintptr_t)dv + slen-1); + } else str=NULL; + memcpy(&((char**)c->addr)[fidx],&str,sizeof(char*)); + } + break; + case TPL_TYPE_POUND: + /* iterate over preceding nodes */ + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + /* in start or midst of loop. advance addr/data pointers. */ + for(np=pd->iter_start_node; np != c; np = np->next) { + np->addr = (char*)(np->addr) + pd->inter_elt_len; + } + /* do next iteration */ + c = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len); + } + + } + break; + case TPL_TYPE_ARY: + if (tpl_serlen(r,c,dv, &A_bytes) == -1) + tpl_hook.fatal("internal error in unpack\n"); + memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t)); + ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + A_bytes); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + c = c->next; + } + if (n->type == TPL_TYPE_ARY) ((tpl_atyp*)(n->data))->cur = dv; /* next element */ + return rc; +} + +/* Specialized function that unpacks only the root's A nodes, after tpl_load */ +static int tpl_unpackA0(tpl_node *r) { + tpl_node *n, *c; + uint32_t slen; + int rc=1,fidx,i; + void *dv; + size_t A_bytes, itermax; + tpl_pound_data *pd; + + n = r; + dv = tpl_find_data_start( ((tpl_root_data*)(r->data))->mmap.text); + + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + for(fidx=0;fidx < c->num; fidx++) { + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + } + break; + case TPL_TYPE_BIN: + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(i=0; inum; i++) { + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT) + slen += 1; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen>1) dv = (void*)((uintptr_t)dv + slen-1); + } + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + case TPL_TYPE_ARY: + if ( tpl_serlen(r,c,dv, &A_bytes) == -1) + tpl_hook.fatal("internal error in unpackA0\n"); + memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t)); + ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + A_bytes); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + return rc; +} + +/* In-place byte order swapping of a word of length "len" bytes */ +static void tpl_byteswap(void *word, int len) { + int i; + char c, *w; + w = (char*)word; + for(i=0; i0) ? rc : 0; + } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && i<8)); + + if (rc<0) { + tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno)); + return -1; + } else if (rc == 0) { + /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */ + return 0; + } else if (i != 8) { + tpl_hook.oops("internal error\n"); + return -1; + } + + if (preamble[0] == 't' && preamble[1] == 'p' && preamble[2] == 'l') { + memcpy(&tpllen,&preamble[4],4); + if (tpl_needs_endian_swap(preamble)) tpl_byteswap(&tpllen,4); + } else { + tpl_hook.oops("tpl_gather_fd_blocking: non-tpl input\n"); + return -1; + } + + /* malloc space for remainder of tpl image (overall length tpllen) + * and read it in + */ + if (tpl_hook.gather_max > 0 && + tpllen > tpl_hook.gather_max) { + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; + } + *sz = tpllen; + if ( (*img = tpl_hook.malloc(tpllen)) == NULL) { + fatal_oom(); + } + + memcpy(*img,preamble,8); /* copy preamble to output buffer */ + i=8; + do { + rc = read(fd,&((*(char**)img)[i]),tpllen-i); + i += (rc>0) ? rc : 0; + } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && iimg); + tpl_hook.free(*gs); + *gs = NULL; + } + return -1; /* error, caller should close fd */ + } + } else if (rc == 0) { + if (*gs) { + tpl_hook.oops("tpl_gather: partial tpl image precedes EOF\n"); + tpl_hook.free((*gs)->img); + tpl_hook.free(*gs); + *gs = NULL; + } + return 0; /* EOF, caller should close fd */ + } else { + /* concatenate any partial tpl from last read with new buffer */ + if (*gs) { + catlen = (*gs)->len + rc; + if (tpl_hook.gather_max > 0 && + catlen > tpl_hook.gather_max) { + tpl_hook.free( (*gs)->img ); + tpl_hook.free( (*gs) ); + *gs = NULL; + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; /* error, caller should close fd */ + } + if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) { + fatal_oom(); + } + memcpy(img + (*gs)->len, buf, rc); + tpl_hook.free(*gs); + *gs = NULL; + } else { + img = buf; + catlen = rc; + } + /* isolate any full tpl(s) in img and invoke cb for each */ + tpl = img; + keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + while (keep_looping) { + if (strncmp("tpl", tpl, 3) != 0) { + tpl_hook.oops("tpl prefix invalid\n"); + if (img != buf) tpl_hook.free(img); + tpl_hook.free(*gs); + *gs = NULL; + return -3; /* error, caller should close fd */ + } + memcpy(&tpllen,&tpl[4],4); + if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4); + if (tpl+tpllen <= img+catlen) { + cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */ + tpl += tpllen; /* point to next tpl image */ + if (cbrc < 0) keep_looping = 0; + else keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + } else keep_looping=0; + } + /* check if app callback requested closure of tpl source */ + if (cbrc < 0) { + tpl_hook.oops("tpl_fd_gather aborted by app callback\n"); + if (img != buf) tpl_hook.free(img); + if (*gs) tpl_hook.free(*gs); + *gs = NULL; + return -4; + } + /* store any leftover, partial tpl fragment for next read */ + if (tpl == img && img != buf) { + /* consumed nothing from img!=buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + (*gs)->img = tpl; + (*gs)->len = catlen; + } else if (tpl < img+catlen) { + /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) { + fatal_oom(); + } + (*gs)->len = img+catlen - tpl; + memcpy( (*gs)->img, tpl, img+catlen - tpl); + /* free partially consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } else { /* tpl(s) fully consumed */ + /* free consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } + } + } +} + +/* gather tpl piecemeal from memory buffer (not fd) e.g., from a lower-level api */ +static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) { + char *img, *tpl; + int keep_looping, cbrc=0; + size_t catlen; + uint32_t tpllen; + + /* concatenate any partial tpl from last read with new buffer */ + if (*gs) { + catlen = (*gs)->len + len; + if (tpl_hook.gather_max > 0 && + catlen > tpl_hook.gather_max) { + tpl_hook.free( (*gs)->img ); + tpl_hook.free( (*gs) ); + *gs = NULL; + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; /* error, caller should stop accepting input from source*/ + } + if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) { + fatal_oom(); + } + memcpy(img + (*gs)->len, buf, len); + tpl_hook.free(*gs); + *gs = NULL; + } else { + img = buf; + catlen = len; + } + /* isolate any full tpl(s) in img and invoke cb for each */ + tpl = img; + keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + while (keep_looping) { + if (strncmp("tpl", tpl, 3) != 0) { + tpl_hook.oops("tpl prefix invalid\n"); + if (img != buf) tpl_hook.free(img); + tpl_hook.free(*gs); + *gs = NULL; + return -3; /* error, caller should stop accepting input from source*/ + } + memcpy(&tpllen,&tpl[4],4); + if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4); + if (tpl+tpllen <= img+catlen) { + cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */ + tpl += tpllen; /* point to next tpl image */ + if (cbrc < 0) keep_looping = 0; + else keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + } else keep_looping=0; + } + /* check if app callback requested closure of tpl source */ + if (cbrc < 0) { + tpl_hook.oops("tpl_mem_gather aborted by app callback\n"); + if (img != buf) tpl_hook.free(img); + if (*gs) tpl_hook.free(*gs); + *gs = NULL; + return -4; + } + /* store any leftover, partial tpl fragment for next read */ + if (tpl == img && img != buf) { + /* consumed nothing from img!=buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + (*gs)->img = tpl; + (*gs)->len = catlen; + } else if (tpl < img+catlen) { + /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) { + fatal_oom(); + } + (*gs)->len = img+catlen - tpl; + memcpy( (*gs)->img, tpl, img+catlen - tpl); + /* free partially consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } else { /* tpl(s) fully consumed */ + /* free consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } + return 1; +} diff --git a/tpl.h b/tpl.h new file mode 100644 index 0000000..e23953b --- /dev/null +++ b/tpl.h @@ -0,0 +1,133 @@ +/* +Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef TPL_H +#define TPL_H + +#include /* size_t */ + +#ifdef __INTEL_COMPILER +#include +#endif /* Intel Compiler efficient memcpy etc */ + +#ifdef _MSC_VER +typedef unsigned int uint32_t; +#else +#include /* uint32_t */ +#endif + +#if defined __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#ifdef TPL_EXPORTS +#define TPL_API __declspec(dllexport) +#else /* */ +#ifdef TPL_NOLIB +#define TPL_API +#else +#define TPL_API __declspec(dllimport) +#endif /* TPL_NOLIB */ +#endif /* TPL_EXPORTS*/ +#else +#define TPL_API +#endif + +/* bit flags (external) */ +#define TPL_FILE (1 << 0) +#define TPL_MEM (1 << 1) +#define TPL_PREALLOCD (1 << 2) +#define TPL_EXCESS_OK (1 << 3) +#define TPL_FD (1 << 4) +#define TPL_UFREE (1 << 5) +#define TPL_DATAPEEK (1 << 6) +#define TPL_FXLENS (1 << 7) +#define TPL_GETSIZE (1 << 8) +/* do not add flags here without renumbering the internal flags! */ + +/* flags for tpl_gather mode */ +#define TPL_GATHER_BLOCKING 1 +#define TPL_GATHER_NONBLOCKING 2 +#define TPL_GATHER_MEM 3 + +/* Hooks for error logging, memory allocation functions and fatal */ +typedef int (tpl_print_fcn)(const char *fmt, ...); +typedef void *(tpl_malloc_fcn)(size_t sz); +typedef void *(tpl_realloc_fcn)(void *ptr, size_t sz); +typedef void (tpl_free_fcn)(void *ptr); +typedef void (tpl_fatal_fcn)(char *fmt, ...); + +typedef struct tpl_hook_t { + tpl_print_fcn *oops; + tpl_malloc_fcn *malloc; + tpl_realloc_fcn *realloc; + tpl_free_fcn *free; + tpl_fatal_fcn *fatal; + size_t gather_max; +} tpl_hook_t; + +typedef struct tpl_node { + int type; + void *addr; + void *data; /* r:tpl_root_data*. A:tpl_atyp*. ow:szof type */ + int num; /* length of type if its a C array */ + size_t ser_osz; /* serialization output size for subtree */ + struct tpl_node *children; /* my children; linked-list */ + struct tpl_node *next,*prev; /* my siblings (next child of my parent) */ + struct tpl_node *parent; /* my parent */ +} tpl_node; + +/* used when un/packing 'B' type (binary buffers) */ +typedef struct tpl_bin { + void *addr; + uint32_t sz; +} tpl_bin; + +/* for async/piecemeal reading of tpl images */ +typedef struct tpl_gather_t { + char *img; + int len; +} tpl_gather_t; + +/* Callback used when tpl_gather has read a full tpl image */ +typedef int (tpl_gather_cb)(void *img, size_t sz, void *data); + +/* Prototypes */ +TPL_API tpl_node *tpl_map(char *fmt,...); /* define tpl using format */ +TPL_API void tpl_free(tpl_node *r); /* free a tpl map */ +TPL_API int tpl_pack(tpl_node *r, int i); /* pack the n'th packable */ +TPL_API int tpl_unpack(tpl_node *r, int i); /* unpack the n'th packable */ +TPL_API int tpl_dump(tpl_node *r, int mode, ...); /* serialize to mem/file */ +TPL_API int tpl_load(tpl_node *r, int mode, ...); /* set mem/file to unpack */ +TPL_API int tpl_Alen(tpl_node *r, int i); /* array len of packable i */ +TPL_API char* tpl_peek(int mode, ...); /* sneak peek at format string */ +TPL_API int tpl_gather( int mode, ...); /* non-blocking image gather */ +TPL_API int tpl_jot(int mode, ...); /* quick write a simple tpl */ + +#if defined __cplusplus + } +#endif + +#endif /* TPL_H */ + diff --git a/utarray.h b/utarray.h new file mode 100644 index 0000000..4dc66ab --- /dev/null +++ b/utarray.h @@ -0,0 +1,232 @@ +/* +Copyright (c) 2008-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + * see http://uthash.sourceforge.net/utarray + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.4 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + const UT_icd *icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + utarray_reserve(a,1); \ + if (j > (a)->i) break; \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) break; \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd->sz)); \ + } \ + if ((a)->icd->copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd->sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd->dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd->init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd->init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr((a),pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ + (((a)->i)-(pos+len))*((a)->icd->sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_renew(a,u) do { \ + if (a) utarray_clear(a); \ + else utarray_new((a),(u)); \ +} while(0); + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd->dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd->sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; +static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/uthash.h b/uthash.h new file mode 100644 index 0000000..ffdc6cd --- /dev/null +++ b/uthash.h @@ -0,0 +1,904 @@ +/* +Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.4 + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + uint32_t _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/utils/.deps/kvsp-export.Po b/utils/.deps/kvsp-export.Po new file mode 100644 index 0000000..a4c8962 --- /dev/null +++ b/utils/.deps/kvsp-export.Po @@ -0,0 +1,197 @@ +kvsp-export.o: kvsp-export.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/signal.h /usr/include/bits/sigset.h \ + /usr/include/bits/signum.h /usr/include/time.h \ + /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/sigthread.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/stdlib.h /usr/include/bits/string3.h \ + /usr/include/sys/types.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h \ + /usr/include/sys/socket.h /usr/include/sys/uio.h /usr/include/bits/uio.h \ + /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/socket2.h /usr/include/netinet/in.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/bits/in.h \ + /usr/include/arpa/inet.h /usr/include/assert.h /usr/include/sys/prctl.h \ + /usr/include/linux/prctl.h ../kvspool_internal.h ../kvspool.h \ + ../uthash.h /usr/include/inttypes.h ../utarray.h ../utarray.h ../tpl.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/signal.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/signum.h: + +/usr/include/time.h: + +/usr/include/bits/siginfo.h: + +/usr/include/bits/sigaction.h: + +/usr/include/bits/sigcontext.h: + +/usr/include/bits/sigstack.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sigthread.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/sys/types.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/sys/socket.h: + +/usr/include/sys/uio.h: + +/usr/include/bits/uio.h: + +/usr/include/bits/socket.h: + +/usr/include/bits/sockaddr.h: + +/usr/include/asm/socket.h: + +/usr/include/asm-generic/socket.h: + +/usr/include/asm/sockios.h: + +/usr/include/asm-generic/sockios.h: + +/usr/include/bits/socket2.h: + +/usr/include/netinet/in.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +/usr/include/bits/in.h: + +/usr/include/arpa/inet.h: + +/usr/include/assert.h: + +/usr/include/sys/prctl.h: + +/usr/include/linux/prctl.h: + +../kvspool_internal.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +../utarray.h: + +../utarray.h: + +../tpl.h: diff --git a/utils/.deps/kvsp-import.Po b/utils/.deps/kvsp-import.Po new file mode 100644 index 0000000..b9a7776 --- /dev/null +++ b/utils/.deps/kvsp-import.Po @@ -0,0 +1,174 @@ +kvsp-import.o: kvsp-import.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/assert.h /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/stdlib.h /usr/include/bits/string3.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h \ + /usr/include/sys/socket.h /usr/include/sys/uio.h /usr/include/bits/uio.h \ + /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/socket2.h /usr/include/netinet/in.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/bits/in.h \ + /usr/include/arpa/inet.h ../kvspool_internal.h ../kvspool.h ../uthash.h \ + /usr/include/inttypes.h ../utarray.h ../utarray.h ../tpl.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/assert.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/sys/socket.h: + +/usr/include/sys/uio.h: + +/usr/include/bits/uio.h: + +/usr/include/bits/socket.h: + +/usr/include/bits/sockaddr.h: + +/usr/include/asm/socket.h: + +/usr/include/asm-generic/socket.h: + +/usr/include/asm/sockios.h: + +/usr/include/asm-generic/sockios.h: + +/usr/include/bits/socket2.h: + +/usr/include/netinet/in.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +/usr/include/bits/in.h: + +/usr/include/arpa/inet.h: + +../kvspool_internal.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +../utarray.h: + +../utarray.h: + +../tpl.h: diff --git a/utils/.deps/kvsp-mod.Po b/utils/.deps/kvsp-mod.Po new file mode 100644 index 0000000..8734d17 --- /dev/null +++ b/utils/.deps/kvsp-mod.Po @@ -0,0 +1,122 @@ +kvsp-mod.o: kvsp-mod.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/string.h /usr/include/xlocale.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h ../utarray.h \ + ../utstring.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: + +../utstring.h: diff --git a/utils/.deps/kvsp-prune.Po b/utils/.deps/kvsp-prune.Po new file mode 100644 index 0000000..a663d88 --- /dev/null +++ b/utils/.deps/kvsp-prune.Po @@ -0,0 +1,118 @@ +kvsp-prune.o: kvsp-prune.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/assert.h /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h ../kvspool.h ../uthash.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h ../utstring.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/assert.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utstring.h: diff --git a/utils/.deps/kvsp-pub.Po b/utils/.deps/kvsp-pub.Po new file mode 100644 index 0000000..66123c9 --- /dev/null +++ b/utils/.deps/kvsp-pub.Po @@ -0,0 +1,179 @@ +kvsp-pub.o: kvsp-pub.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/signal.h /usr/include/bits/sigset.h \ + /usr/include/bits/signum.h /usr/include/time.h \ + /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/sigthread.h \ + /usr/include/sys/types.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/sys/wait.h /usr/include/sys/resource.h \ + /usr/include/bits/resource.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/sys/prctl.h \ + /usr/include/linux/prctl.h /usr/include/assert.h /usr/include/xlocale.h \ + /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/stdlib.h \ + /usr/include/bits/string3.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/local/include/zmq.h \ + ../utarray.h ../kvspool_internal.h ../kvspool.h ../uthash.h \ + /usr/include/inttypes.h /usr/include/stdint.h /usr/include/bits/wchar.h \ + ../utarray.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/signal.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/signum.h: + +/usr/include/time.h: + +/usr/include/bits/siginfo.h: + +/usr/include/bits/sigaction.h: + +/usr/include/bits/sigcontext.h: + +/usr/include/bits/sigstack.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/sigthread.h: + +/usr/include/sys/types.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/sys/wait.h: + +/usr/include/sys/resource.h: + +/usr/include/bits/resource.h: + +/usr/include/bits/waitflags.h: + +/usr/include/bits/waitstatus.h: + +/usr/include/sys/prctl.h: + +/usr/include/linux/prctl.h: + +/usr/include/assert.h: + +/usr/include/xlocale.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/local/include/zmq.h: + +../utarray.h: + +../kvspool_internal.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: diff --git a/utils/.deps/kvsp-reset.Po b/utils/.deps/kvsp-reset.Po new file mode 100644 index 0000000..3485d4b --- /dev/null +++ b/utils/.deps/kvsp-reset.Po @@ -0,0 +1,117 @@ +kvsp-reset.o: kvsp-reset.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/string.h /usr/include/xlocale.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: diff --git a/utils/.deps/kvsp-size.Po b/utils/.deps/kvsp-size.Po new file mode 100644 index 0000000..89deea5 --- /dev/null +++ b/utils/.deps/kvsp-size.Po @@ -0,0 +1,136 @@ +kvsp-size.o: kvsp-size.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/assert.h /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/stdlib.h /usr/include/bits/string3.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/inttypes.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h ../utstring.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/assert.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utstring.h: diff --git a/utils/.deps/kvsp-speed.Po b/utils/.deps/kvsp-speed.Po new file mode 100644 index 0000000..5d8d787 --- /dev/null +++ b/utils/.deps/kvsp-speed.Po @@ -0,0 +1,119 @@ +kvsp-speed.o: kvsp-speed.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/bits/stdlib.h /usr/include/xlocale.h \ + ../kvspool.h ../uthash.h /usr/include/string.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/sys/time.h: + +/usr/include/time.h: + +/usr/include/bits/time.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/xlocale.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: diff --git a/utils/.deps/kvsp-split.Po b/utils/.deps/kvsp-split.Po new file mode 100644 index 0000000..96aacea --- /dev/null +++ b/utils/.deps/kvsp-split.Po @@ -0,0 +1,122 @@ +kvsp-split.o: kvsp-split.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/string.h /usr/include/xlocale.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h ../utarray.h \ + ../utstring.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: + +../utstring.h: diff --git a/utils/.deps/kvsp-spr.Po b/utils/.deps/kvsp-spr.Po new file mode 100644 index 0000000..d75ff24 --- /dev/null +++ b/utils/.deps/kvsp-spr.Po @@ -0,0 +1,123 @@ +kvsp-spr.o: kvsp-spr.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/assert.h /usr/include/stdlib.h /usr/include/sys/types.h \ + /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool_internal.h \ + ../kvspool.h ../uthash.h /usr/include/string.h /usr/include/xlocale.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h ../utarray.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/assert.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool_internal.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: diff --git a/utils/.deps/kvsp-spw.Po b/utils/.deps/kvsp-spw.Po new file mode 100644 index 0000000..46ee737 --- /dev/null +++ b/utils/.deps/kvsp-spw.Po @@ -0,0 +1,117 @@ +kvsp-spw.o: kvsp-spw.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h /usr/include/getopt.h \ + /usr/include/bits/unistd.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/bits/stdlib.h /usr/include/xlocale.h \ + ../kvspool.h ../uthash.h /usr/include/string.h \ + /usr/include/bits/string.h /usr/include/bits/string2.h \ + /usr/include/bits/string3.h /usr/include/inttypes.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/xlocale.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: diff --git a/utils/.deps/kvsp-status.Po b/utils/.deps/kvsp-status.Po new file mode 100644 index 0000000..44010ac --- /dev/null +++ b/utils/.deps/kvsp-status.Po @@ -0,0 +1,156 @@ +kvsp-status.o: kvsp-status.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/assert.h /usr/include/sys/types.h /usr/include/time.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/sys/stat.h \ + /usr/include/bits/stat.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \ + /usr/include/bits/fcntl2.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/string.h \ + /usr/include/xlocale.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/stdlib.h \ + /usr/include/bits/string3.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/inttypes.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h ../kvspool_internal.h ../kvspool.h \ + ../utarray.h ../utarray.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/assert.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/sys/stat.h: + +/usr/include/bits/stat.h: + +/usr/include/fcntl.h: + +/usr/include/bits/fcntl.h: + +/usr/include/bits/fcntl2.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../kvspool_internal.h: + +../kvspool.h: + +../utarray.h: + +../utarray.h: diff --git a/utils/.deps/kvsp-sub.Po b/utils/.deps/kvsp-sub.Po new file mode 100644 index 0000000..c42330d --- /dev/null +++ b/utils/.deps/kvsp-sub.Po @@ -0,0 +1,145 @@ +kvsp-sub.o: kvsp-sub.c /usr/include/unistd.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/confname.h /usr/include/getopt.h \ + /usr/include/bits/unistd.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h /usr/include/bits/stdlib.h /usr/include/assert.h \ + /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/xlocale.h /usr/local/include/zmq.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h ../kvspool_internal.h ../kvspool.h \ + ../uthash.h /usr/include/string.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/bits/string3.h \ + /usr/include/inttypes.h /usr/include/stdint.h /usr/include/bits/wchar.h \ + ../utarray.h ../utstring.h ../uthash.h + +/usr/include/unistd.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +/usr/include/stdlib.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/assert.h: + +/usr/include/stdio.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/xlocale.h: + +/usr/local/include/zmq.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +../kvspool_internal.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/string.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/bits/string3.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: + +../utstring.h: + +../uthash.h: diff --git a/utils/.deps/kvsp-tee.Po b/utils/.deps/kvsp-tee.Po new file mode 100644 index 0000000..b017a0f --- /dev/null +++ b/utils/.deps/kvsp-tee.Po @@ -0,0 +1,134 @@ +kvsp-tee.o: kvsp-tee.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h /usr/include/bits/stdio2.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/bits/string.h \ + /usr/include/bits/string2.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ + /usr/include/stdlib.h /usr/include/bits/string3.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ + /usr/include/getopt.h /usr/include/bits/unistd.h ../kvspool.h \ + ../uthash.h /usr/include/inttypes.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h ../utarray.h + +/usr/include/stdio.h: + +/usr/include/features.h: + +/usr/include/bits/predefs.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stddef.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/libio.h: + +/usr/include/_G_config.h: + +/usr/include/wchar.h: + +/usr/lib/gcc/x86_64-linux-gnu/4.4.3/include/stdarg.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +/usr/include/bits/stdio2.h: + +/usr/include/errno.h: + +/usr/include/bits/errno.h: + +/usr/include/linux/errno.h: + +/usr/include/asm/errno.h: + +/usr/include/asm-generic/errno.h: + +/usr/include/asm-generic/errno-base.h: + +/usr/include/string.h: + +/usr/include/xlocale.h: + +/usr/include/bits/string.h: + +/usr/include/bits/string2.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/stdlib.h: + +/usr/include/bits/string3.h: + +/usr/include/sys/types.h: + +/usr/include/time.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/sigset.h: + +/usr/include/bits/time.h: + +/usr/include/sys/sysmacros.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/alloca.h: + +/usr/include/bits/stdlib.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/confname.h: + +/usr/include/getopt.h: + +/usr/include/bits/unistd.h: + +../kvspool.h: + +../uthash.h: + +/usr/include/inttypes.h: + +/usr/include/stdint.h: + +/usr/include/bits/wchar.h: + +../utarray.h: diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100644 index 0000000..5f46c7d --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1,11 @@ +kvsp-tee +kvsp-prune +kvsp-export +kvsp-import +kvsp-speed +kvsp-status +kvsp-mod +kvsp-reset +kvsp-split +kvsp-spr +kvsp-spw diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 0000000..94d7a26 --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,25 @@ +AM_CFLAGS = -I.. +LDADD = -L.. -lkvspool +bin_PROGRAMS = kvsp-spr kvsp-spw kvsp-tee kvsp-size kvsp-status \ + kvsp-import kvsp-export kvsp-speed kvsp-split kvsp-mod kvsp-reset + +if HAVE_ZEROMQ +bin_PROGRAMS += kvsp-sub kvsp-pub +kvsp_pub_LDADD = $(LDADD) -lzmq +kvsp_sub_LDADD = $(LDADD) -lzmq +endif + +# to get a rebuild of the utilities when ../libkvspool.a changes: +kvsp_spr_DEPENDENCIES = ../libkvspool.a +kvsp_spw_DEPENDENCIES = ../libkvspool.a +kvsp_tee_DEPENDENCIES = ../libkvspool.a +kvsp_size_DEPENDENCIES = ../libkvspool.a +kvsp_status_DEPENDENCIES = ../libkvspool.a +kvsp_export_DEPENDENCIES = ../libkvspool.a +kvsp_import_DEPENDENCIES = ../libkvspool.a +kvsp_speed_DEPENDENCIES = ../libkvspool.a +kvsp_split_DEPENDENCIES = ../libkvspool.a +kvsp_mod_DEPENDENCIES = ../libkvspool.a +kvsp_reset_DEPENDENCIES = ../libkvspool.a +kvsp_sub_DEPENDENCIES = ../libkvspool.a +kvsp_pub_DEPENDENCIES = ../libkvspool.a diff --git a/utils/Makefile.in b/utils/Makefile.in new file mode 100644 index 0000000..e80c6bb --- /dev/null +++ b/utils/Makefile.in @@ -0,0 +1,566 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@ +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 = : +bin_PROGRAMS = kvsp-spr$(EXEEXT) kvsp-spw$(EXEEXT) kvsp-tee$(EXEEXT) \ + kvsp-size$(EXEEXT) kvsp-status$(EXEEXT) kvsp-import$(EXEEXT) \ + kvsp-export$(EXEEXT) kvsp-speed$(EXEEXT) kvsp-split$(EXEEXT) \ + kvsp-mod$(EXEEXT) kvsp-reset$(EXEEXT) $(am__EXEEXT_1) +@HAVE_ZEROMQ_TRUE@am__append_1 = kvsp-sub kvsp-pub +subdir = utils +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/python.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_ZEROMQ_TRUE@am__EXEEXT_1 = kvsp-sub$(EXEEXT) kvsp-pub$(EXEEXT) +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +kvsp_export_SOURCES = kvsp-export.c +kvsp_export_OBJECTS = kvsp-export.$(OBJEXT) +kvsp_export_LDADD = $(LDADD) +kvsp_import_SOURCES = kvsp-import.c +kvsp_import_OBJECTS = kvsp-import.$(OBJEXT) +kvsp_import_LDADD = $(LDADD) +kvsp_mod_SOURCES = kvsp-mod.c +kvsp_mod_OBJECTS = kvsp-mod.$(OBJEXT) +kvsp_mod_LDADD = $(LDADD) +kvsp_pub_SOURCES = kvsp-pub.c +kvsp_pub_OBJECTS = kvsp-pub.$(OBJEXT) +am__DEPENDENCIES_1 = +kvsp_reset_SOURCES = kvsp-reset.c +kvsp_reset_OBJECTS = kvsp-reset.$(OBJEXT) +kvsp_reset_LDADD = $(LDADD) +kvsp_size_SOURCES = kvsp-size.c +kvsp_size_OBJECTS = kvsp-size.$(OBJEXT) +kvsp_size_LDADD = $(LDADD) +kvsp_speed_SOURCES = kvsp-speed.c +kvsp_speed_OBJECTS = kvsp-speed.$(OBJEXT) +kvsp_speed_LDADD = $(LDADD) +kvsp_split_SOURCES = kvsp-split.c +kvsp_split_OBJECTS = kvsp-split.$(OBJEXT) +kvsp_split_LDADD = $(LDADD) +kvsp_spr_SOURCES = kvsp-spr.c +kvsp_spr_OBJECTS = kvsp-spr.$(OBJEXT) +kvsp_spr_LDADD = $(LDADD) +kvsp_spw_SOURCES = kvsp-spw.c +kvsp_spw_OBJECTS = kvsp-spw.$(OBJEXT) +kvsp_spw_LDADD = $(LDADD) +kvsp_status_SOURCES = kvsp-status.c +kvsp_status_OBJECTS = kvsp-status.$(OBJEXT) +kvsp_status_LDADD = $(LDADD) +kvsp_sub_SOURCES = kvsp-sub.c +kvsp_sub_OBJECTS = kvsp-sub.$(OBJEXT) +kvsp_tee_SOURCES = kvsp-tee.c +kvsp_tee_OBJECTS = kvsp-tee.$(OBJEXT) +kvsp_tee_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = kvsp-export.c kvsp-import.c kvsp-mod.c kvsp-pub.c \ + kvsp-reset.c kvsp-size.c kvsp-speed.c kvsp-split.c kvsp-spr.c \ + kvsp-spw.c kvsp-status.c kvsp-sub.c kvsp-tee.c +DIST_SOURCES = kvsp-export.c kvsp-import.c kvsp-mod.c kvsp-pub.c \ + kvsp-reset.c kvsp-size.c kvsp-speed.c kvsp-split.c kvsp-spr.c \ + kvsp-spw.c kvsp-status.c kvsp-sub.c kvsp-tee.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +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@ +PERL = @PERL@ +PYTHON = @PYTHON@ +PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@ +PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@ +PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@ +PYTHON_LDFLAGS = @PYTHON_LDFLAGS@ +PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +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_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +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@ +AM_CFLAGS = -I.. +LDADD = -L.. -lkvspool +@HAVE_ZEROMQ_TRUE@kvsp_pub_LDADD = $(LDADD) -lzmq +@HAVE_ZEROMQ_TRUE@kvsp_sub_LDADD = $(LDADD) -lzmq + +# to get a rebuild of the utilities when ../libkvspool.a changes: +kvsp_spr_DEPENDENCIES = ../libkvspool.a +kvsp_spw_DEPENDENCIES = ../libkvspool.a +kvsp_tee_DEPENDENCIES = ../libkvspool.a +kvsp_size_DEPENDENCIES = ../libkvspool.a +kvsp_status_DEPENDENCIES = ../libkvspool.a +kvsp_export_DEPENDENCIES = ../libkvspool.a +kvsp_import_DEPENDENCIES = ../libkvspool.a +kvsp_speed_DEPENDENCIES = ../libkvspool.a +kvsp_split_DEPENDENCIES = ../libkvspool.a +kvsp_mod_DEPENDENCIES = ../libkvspool.a +kvsp_reset_DEPENDENCIES = ../libkvspool.a +kvsp_sub_DEPENDENCIES = ../libkvspool.a +kvsp_pub_DEPENDENCIES = ../libkvspool.a +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(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 utils/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign utils/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +kvsp-export$(EXEEXT): $(kvsp_export_OBJECTS) $(kvsp_export_DEPENDENCIES) + @rm -f kvsp-export$(EXEEXT) + $(LINK) $(kvsp_export_OBJECTS) $(kvsp_export_LDADD) $(LIBS) +kvsp-import$(EXEEXT): $(kvsp_import_OBJECTS) $(kvsp_import_DEPENDENCIES) + @rm -f kvsp-import$(EXEEXT) + $(LINK) $(kvsp_import_OBJECTS) $(kvsp_import_LDADD) $(LIBS) +kvsp-mod$(EXEEXT): $(kvsp_mod_OBJECTS) $(kvsp_mod_DEPENDENCIES) + @rm -f kvsp-mod$(EXEEXT) + $(LINK) $(kvsp_mod_OBJECTS) $(kvsp_mod_LDADD) $(LIBS) +kvsp-pub$(EXEEXT): $(kvsp_pub_OBJECTS) $(kvsp_pub_DEPENDENCIES) + @rm -f kvsp-pub$(EXEEXT) + $(LINK) $(kvsp_pub_OBJECTS) $(kvsp_pub_LDADD) $(LIBS) +kvsp-reset$(EXEEXT): $(kvsp_reset_OBJECTS) $(kvsp_reset_DEPENDENCIES) + @rm -f kvsp-reset$(EXEEXT) + $(LINK) $(kvsp_reset_OBJECTS) $(kvsp_reset_LDADD) $(LIBS) +kvsp-size$(EXEEXT): $(kvsp_size_OBJECTS) $(kvsp_size_DEPENDENCIES) + @rm -f kvsp-size$(EXEEXT) + $(LINK) $(kvsp_size_OBJECTS) $(kvsp_size_LDADD) $(LIBS) +kvsp-speed$(EXEEXT): $(kvsp_speed_OBJECTS) $(kvsp_speed_DEPENDENCIES) + @rm -f kvsp-speed$(EXEEXT) + $(LINK) $(kvsp_speed_OBJECTS) $(kvsp_speed_LDADD) $(LIBS) +kvsp-split$(EXEEXT): $(kvsp_split_OBJECTS) $(kvsp_split_DEPENDENCIES) + @rm -f kvsp-split$(EXEEXT) + $(LINK) $(kvsp_split_OBJECTS) $(kvsp_split_LDADD) $(LIBS) +kvsp-spr$(EXEEXT): $(kvsp_spr_OBJECTS) $(kvsp_spr_DEPENDENCIES) + @rm -f kvsp-spr$(EXEEXT) + $(LINK) $(kvsp_spr_OBJECTS) $(kvsp_spr_LDADD) $(LIBS) +kvsp-spw$(EXEEXT): $(kvsp_spw_OBJECTS) $(kvsp_spw_DEPENDENCIES) + @rm -f kvsp-spw$(EXEEXT) + $(LINK) $(kvsp_spw_OBJECTS) $(kvsp_spw_LDADD) $(LIBS) +kvsp-status$(EXEEXT): $(kvsp_status_OBJECTS) $(kvsp_status_DEPENDENCIES) + @rm -f kvsp-status$(EXEEXT) + $(LINK) $(kvsp_status_OBJECTS) $(kvsp_status_LDADD) $(LIBS) +kvsp-sub$(EXEEXT): $(kvsp_sub_OBJECTS) $(kvsp_sub_DEPENDENCIES) + @rm -f kvsp-sub$(EXEEXT) + $(LINK) $(kvsp_sub_OBJECTS) $(kvsp_sub_LDADD) $(LIBS) +kvsp-tee$(EXEEXT): $(kvsp_tee_OBJECTS) $(kvsp_tee_DEPENDENCIES) + @rm -f kvsp-tee$(EXEEXT) + $(LINK) $(kvsp_tee_OBJECTS) $(kvsp_tee_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-export.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-import.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-mod.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-pub.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-reset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-size.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-speed.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-split.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-spr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-spw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-status.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-sub.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvsp-tee.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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 +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + 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" + +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 $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +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-binPROGRAMS clean-generic 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-binPROGRAMS + +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 + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + 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 pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS + + +# 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/utils/kvsp-export.c b/utils/kvsp-export.c new file mode 100644 index 0000000..84e2bb6 --- /dev/null +++ b/utils/kvsp-export.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kvspool_internal.h" +#include "utarray.h" +#include "tpl.h" + +#define SPOOL_EXPORT_DEFAULT_PORT 3339 +#define STATS_INTERVAL 1000000 + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-l ] [-p ] [-b base] spool\n", prog); + fprintf(stderr, " -l listen on given IP (def: all IP's)\n"); + fprintf(stderr, " -p listen on given port (def:%d)\n", + (int)SPOOL_EXPORT_DEFAULT_PORT); + fprintf(stderr, " -b only export given base (def: all)\n"); + exit(-1); +} + +char proctitle[16]; +void update_stats(time_t *start, long *count) { + time_t now = time(NULL); + long elapsed = now - *start; + if (elapsed == 0) return; + unsigned kfps = *count / (1024 * elapsed); + snprintf(proctitle,sizeof(proctitle),"export %u kfps", kfps); + prctl(PR_SET_NAME,(unsigned long)proctitle,0,0,0); + fprintf(stderr, "export %u kfps\n", kfps); + *start = now; + *count = 0; +} + +int setup_listener(char *ip_str, int port) { + /********************************************************** + * create an IPv4/TCP socket, not yet bound to any address + *********************************************************/ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + printf("socket: %s\n", strerror(errno)); + return -1; + } + + /********************************************************** + * internet socket address structure: our address and port + *********************************************************/ + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); /* TODO use ip_str */ + sin.sin_port = htons(port); + + /********************************************************** + * bind socket to address and port we'd like to receive on + *********************************************************/ + int optval = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { + printf("bind: %s\n", strerror(errno)); + close(fd); + return -1; + } + + /********************************************************** + * put socket into listening state + *********************************************************/ + if (listen(fd,1) == -1) { + printf("listen: %s\n", strerror(errno)); + close(fd); + return -1; + } + return fd; +} + +char *last_base=NULL; +int export_frame(void *img, size_t sz, char *base, int fd) { + int rc; + if (last_base != base) { /* yes just a pointer compare */ + if (tpl_jot(TPL_FD, fd, "s", &base) == -1) return -1; + last_base = base; + } + + char *buf = (char*)img; + while (sz) { + rc = write(fd, buf, sz); + if (rc == -1 && (errno == EAGAIN || errno == EINTR)) continue; + if (rc == -1) return -1; + sz -= rc; buf += rc; + } + free(img); + return 0; +} + +int main(int argc, char * argv[]) { + int opt,verbose=0,client_fd=-1,listen_fd=-1,tryagain=0; + void *set; + char *ip_str=NULL; + int port=SPOOL_EXPORT_DEFAULT_PORT; + long count=0; + /* exported spool */ + char *dir=NULL; + char *base=NULL; + void *sp; + time_t start = time(NULL); + + signal(SIGPIPE,SIG_IGN); + + set = kv_set_new(); + + while ( (opt = getopt(argc, argv, "v+l:p:b:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'l': ip_str = strdup(optarg); break; + case 'p': port = atoi(optarg); break; + case 'b': base = strdup(optarg); break; + default: usage(argv[0]); break; + } + } + if (optind < argc) dir = argv[optind++]; + if (dir==NULL) usage(argv[0]); + sp = kv_spoolreader_new(dir,base); + if (sp == NULL) { + fprintf(stderr, "failed to open input spool %s\n", dir); + goto done; + } + + listen_fd = setup_listener(ip_str,port); + if (listen_fd == -1) goto done; + + while (1) { + struct sockaddr_in cin; + socklen_t cin_sz = sizeof(cin); + client_fd = accept(listen_fd, (struct sockaddr*)&cin, &cin_sz); + if (client_fd == -1) { + fprintf(stderr,"accept: %s\n",strerror(errno)); + continue; + } + if (sizeof(cin)==cin_sz) printf("connection from %s:%d\n", + inet_ntoa(cin.sin_addr), (int)ntohs(cin.sin_port)); + + last_base=NULL; + while (tryagain || (kv_spool_read(sp,set,1) == 1)) { + kvset_t *_set = (kvset_t*)set; + if (export_frame(_set->img,_set->len,_set->base,client_fd) == -1) { + tryagain=1; + close(client_fd); client_fd=-1; + break; + } + tryagain=0; + if ((++count % STATS_INTERVAL) == 0) update_stats(&start,&count); + } + } + + done: + if (listen_fd != -1) close(listen_fd); + if (client_fd != -1) close(client_fd); + kv_set_free(set); + kv_spoolreader_free(sp); + return 0; +} + diff --git a/utils/kvsp-import.c b/utils/kvsp-import.c new file mode 100644 index 0000000..3209720 --- /dev/null +++ b/utils/kvsp-import.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../kvspool_internal.h" +#include "utarray.h" +#include "tpl.h" + +#define SPOOL_EXPORT_DEFAULT_PORT 3339 + +typedef struct { + char *base; + void *sp; +} ospool_base_t; + +/* plumbing for ospool_base_t array */ +void ospool_base_ini(void *_ospb) { + ospool_base_t *ospb = (ospool_base_t*)_ospb; + ospb->base=NULL; + ospb->sp=NULL; +} +void ospool_base_cpy(void *_dst, const void *_src) { + assert(0); /* enforce that this function is not used */ + /* note that copy is not used here because dst->sp has + * no ref counting support; but our 'fin' frees it. */ + +} +void ospool_base_fin(void *_ospb) { + ospool_base_t *ospb = (ospool_base_t*)_ospb; + if (ospb->base) free(ospb->base); + if (ospb->sp) kv_spoolwriter_free(ospb->sp); +} + +UT_icd ospool_base_icd = {sizeof(ospool_base_t), + ospool_base_ini, + ospool_base_cpy, + ospool_base_fin}; + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] -s [-p ] spool\n", prog); + fprintf(stderr, " -s connect to given IP\n"); + fprintf(stderr, " -p listen on given port (def:%d)\n", + (int)SPOOL_EXPORT_DEFAULT_PORT); + exit(-1); +} + +int connect_to_exporter(char *ip_str, int port) { + /********************************************************** + * create an IPv4/TCP socket, not yet bound to any address + *********************************************************/ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + fprintf(stderr,"socket: %s\n", strerror(errno)); + return -1; + } + /********************************************************** + * internet socket address structure, for the remote side + *********************************************************/ + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(ip_str); + sin.sin_port = htons(port); + + if (sin.sin_addr.s_addr == INADDR_NONE) { + fprintf(stderr,"invalid remote IP %s\n", ip_str); + close(fd); + return -1; + } + + /********************************************************** + * Perform the 3 way handshake, (c)syn, (s)ack/syn, c(ack) + *********************************************************/ + if (connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { + fprintf(stderr,"connect: %s\n", strerror(errno)); + close(fd); + return -1; + } + + return fd; +} + +int main(int argc, char * argv[]) { + int rc, opt,verbose=0,server_fd=-1; + void *set,*img; + size_t sz; + char *ip_str=NULL; + int port=SPOOL_EXPORT_DEFAULT_PORT; + char *dir=NULL,*base=NULL; + + UT_array *ospoolv; + utarray_new(ospoolv, &ospool_base_icd); + + set = kv_set_new(); + + while ( (opt = getopt(argc, argv, "v+s:p:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 's': ip_str = strdup(optarg); break; + case 'p': port = atoi(optarg); break; + default: usage(argv[0]); break; + } + } + if (optind < argc) dir = argv[optind++]; + if (dir==NULL) usage(argv[0]); + + /* connect to the listening exporter */ + server_fd = connect_to_exporter(ip_str,port); + if (server_fd == -1) { + fprintf(stderr,"can't connect to server\n"); + goto done; + } + + + while(1) { + if (tpl_gather(TPL_GATHER_BLOCKING, server_fd, &img, &sz) <= 0) { + fprintf(stderr,"closing connection to server\n"); + goto done; + } + + /* is it a base specification? this is a no-op if not */ + char *_base; + char *fmt = tpl_peek(TPL_MEM|TPL_DATAPEEK, img, sz, "s", &_base); + if (fmt) { + if (base) free(base); + base = _base; + free(fmt); + free(img); + continue; + } + + assert(base); + /* find spool writer for this base and write out the frame */ + ospool_base_t *o=NULL; + while( (o=(ospool_base_t*)utarray_next(ospoolv,o))) { + if (strcmp(o->base,base)) continue; + break; + } + if (o == NULL) { /* don't have one already; make one */ + utarray_extend_back(ospoolv); + o = (ospool_base_t*)utarray_back(ospoolv); + o->base = strdup(base); + o->sp = kv_spoolwriter_new(dir,base); + if (!o->sp) { + fprintf(stderr,"failed to open output spool %s base %s\n",dir,base); + goto done; + } + } + kv_write_raw_frame(o->sp,img,sz); + free(img); + } + + done: + if (server_fd != -1) close(server_fd); + utarray_free(ospoolv); + kv_set_free(set); + return 0; +} + diff --git a/utils/kvsp-mod.c b/utils/kvsp-mod.c new file mode 100644 index 0000000..24bfd76 --- /dev/null +++ b/utils/kvsp-mod.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utstring.h" + +int verbose=0; +char *base = NULL; +char *dir = NULL; +char *conf = NULL; +char *odir = "."; +int block=1; +UT_array *keys; + +typedef struct { + char *base; + void *sp; + UT_hash_handle hh; +} osp_t; + +osp_t *ospv = NULL; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-v] [-b base] -k " + "[-k ...] [-o outdir] \n", exe); + exit(-1); +} + +void *get_output_spool(char *base) { + osp_t *osp; + HASH_FIND_STR(ospv,base,osp); + if (!osp) { + osp = malloc(sizeof(*osp)); if (!osp) goto done; + osp->sp = kv_spoolwriter_new(odir,base); + if (osp->sp == NULL) { free(osp); osp=NULL; goto done;} + osp->base = strdup(base); + HASH_ADD_KEYPTR(hh,ospv,osp->base,strlen(base),osp); + } + done: + return osp ? osp->sp : NULL; +} + +int main(int argc, char *argv[]) { + + kv_t *kv; + int opt,rc; + osp_t *osp, *tmp; + char *exe = argv[0]; + utarray_new(keys,&ut_str_icd); + + while ( (opt = getopt(argc, argv, "b:v+k:c:n:o:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'b': base=strdup(optarg); break; + case 'c': conf=strdup(optarg); break; + case 'o': odir=strdup(optarg); break; + case 'k': utarray_push_back(keys,&optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + else usage(exe); + + void *sp = kv_spoolreader_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + while ( (rc=kv_spool_read(sp,set,block)) > 0) { + /* calculate hash value of keys */ + char *key, *val, **k=NULL; + while ( (k=(char**)utarray_next(keys,k))) { + key = *k; + kv = kv_get(set, key); + if (!kv) {if (verbose) fprintf(stderr,"no such key: %s; skipping\n", key); continue;} + /* replace the value with a hash of the value */ + unsigned hv=0, vlen=kv->vlen; val = kv->val; + while(vlen--) hv = hv * 33 + *val++; + // we could write it in binary but we change it to text + //kv_add(set, kv->key, kv->klen, (void*)&hv, sizeof(hv)); + char hv_str[10]; + snprintf(hv_str,sizeof(hv_str),"%u",hv); + kv_add(set, kv->key, kv->klen, hv_str, strlen(hv_str)); + } + char *sbase = kv_set_base(set); + osp = get_output_spool(sbase); + if (kv_spool_write(osp, set) != 0) {printf("output error\n"); break; } + } + + /* clean up */ + HASH_ITER(hh,ospv,osp,tmp) { + HASH_DEL(ospv, osp); + free(osp->base); + kv_spoolwriter_free(osp->sp); + } + kv_spoolreader_free(sp); + kv_set_free(set); + utarray_free(keys); + return 0; +} diff --git a/utils/kvsp-pub.c b/utils/kvsp-pub.c new file mode 100644 index 0000000..898db82 --- /dev/null +++ b/utils/kvsp-pub.c @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utarray.h" +#include "kvspool_internal.h" + +/****************************************************************************** + * kvsp-publish + * This program monitors multiple spools using a pool of readers + * Whenever a spool has a frame that's readable it is published to subscribers + *****************************************************************************/ + +typedef struct { + pid_t pid; + time_t start; + char *dir; + char *transport; +} worker_t; + +#define SHORT_DELAY 10 +const uint64_t hwm = 10000; /* high water mark: max messages pub will buffer */ + +worker_t *workers; +int wn=1; /* workers needed: 1 device + 1 publisher per spool */ +int verbose; +char *file; +char *pub_transport; /* client kvsp-sub's connect to us on this transport */ +UT_array *dirs; + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] \n", prog); + fprintf(stderr, " is a 0mq path e.g. tcp://localhost:1234\n"); + fprintf(stderr, " is '-d [-d ...]' or -f \n"); + exit(-1); +} + +void configure_worker(int n) { + worker_t *w = &workers[n]; + char transport[100]; + snprintf(transport,sizeof(transport),"ipc://kvsp-pub-%u:%u",(int)getpid(),n); + w->transport = strdup(transport); + w->dir = strdup(*(char**)utarray_eltptr(dirs,n-1)); + fprintf(stderr,"setting transport %s\n", w->transport); +} + +/* one special sub-process runs the 'device': subscriber/central republisher */ +void device(void) { + int n,rc=-1; + void *dev_context=NULL; + void *sub_socket=NULL,*pub_socket=NULL; + if ( !(dev_context = zmq_init(1))) goto done; + if ( !(sub_socket = zmq_socket(dev_context, ZMQ_SUB))) goto done; + if ( !(pub_socket = zmq_socket(dev_context, ZMQ_PUB))) goto done; + + /* connect the subscriber socket to each of the workers. then subscribe it */ + for(n=1;n 0) { /* parent. */ + /* record worker */ + workers[w].pid = pid; + workers[w].start = time(NULL); + return; + } + + /* child here */ + + /* unblock all signals */ + sigset_t all; + sigemptyset(&all); + sigprocmask(SIG_SETMASK,&all,NULL); + + char name[16]; + snprintf(name,sizeof(name),"kvsp-pub: %s", w ? workers[w].dir : "device"); + prctl(PR_SET_NAME,name); + prctl(PR_SET_PDEATHSIG, SIGHUP); // TODO clean shutdown on HUP + + if (w == 0) device(); // never returns + + void *_set = kv_set_new(); + void *sp = kv_spoolreader_new(workers[w].dir,NULL); + if (!sp) goto done; + + /* prepare for ZMQ publishing */ + void *pub_context; + void *pub_socket; + if ( !(pub_context = zmq_init(1))) goto done; + if ( !(pub_socket = zmq_socket(pub_context, ZMQ_PUB))) goto done; + if (zmq_bind(pub_socket, workers[w].transport) == -1) goto done; + + while (kv_spool_read(sp,_set,1) > 0) { /* read til interrupted by signal */ + kvset_t *set = (kvset_t*)_set; + assert(set->img && set->len); + assert(set->base); + + zmq_msg_t part; + + rc = zmq_msg_init_size(&part, strlen(set->base)); assert(!rc); + memcpy(zmq_msg_data(&part), set->base, strlen(set->base)); + rc = zmq_send(pub_socket, &part, ZMQ_SNDMORE); + zmq_msg_close(&part); + if(rc) goto done; + + rc = zmq_msg_init_size(&part, set->len); assert(!rc); + memcpy(zmq_msg_data(&part), set->img, set->len); + rc = zmq_send(pub_socket, &part, 0); + zmq_msg_close(&part); + if(rc) goto done; + } + + rc=0; + + done: + // TODO avoid printing to parent stderr (kv lib does; so dup fd to logging) + if (rc) fprintf(stderr,"zmq: %s %s\n", pub_transport, zmq_strerror(errno)); + if (pub_socket) zmq_close(pub_socket); + if (pub_context) zmq_term(pub_context); + if (sp) kv_spoolreader_free(sp); + kv_set_free(_set); + + exit(rc); /* do not return */ +} + +void run_workers() { + int n; + for(n=0; n < wn; n++) { + if (workers[n].pid) continue; + worker(n); + } +} + + +void fini_workers() { + int n,es; + for(n=0; n < wn; n++) { + worker_t *w = &workers[n]; + if (w->pid == 0) goto release; + kill(w->pid, SIGTERM); + if (waitpid(w->pid, &es, WNOHANG) == w->pid) w->pid = 0; + else { /* child didn't exit. give it a moment, then force quit. */ + sleep(1); + kill(w->pid, SIGKILL); + if (waitpid(w->pid, &es, WNOHANG) == w->pid) w->pid = 0; + } + if(w->pid) fprintf(stderr, "can't terminate pid %d (%s): %s\n",(int)w->pid,w->dir,strerror(errno)); + else if (WIFSIGNALED(es)) fprintf(stderr,"exited on signal %d", (int)WTERMSIG(es)); + else if (WIFEXITED(es)) fprintf(stderr,"exit status %d", (int)WEXITSTATUS(es)); + + release: + free(w->dir); + free(w->transport); + } +} + +void read_conf(char *file) { + char line[200], *linep = line; + int len; + FILE *f; + + if ( (f = fopen(file,"r")) == NULL) { + fprintf(stderr,"can't open %s: %s\n", file, strerror(errno)); + exit(-1); + } + while (fgets(line,sizeof(line),f) != NULL) { + len = strlen(line); + if (len && (line[len-1]=='\n')) line[--len] = '\0'; + if (len) utarray_push_back(dirs,&linep); + } +} + +int main(int argc, char *argv[]) { + char *file, *dir; + int n,opt,es,defer_restart; + pid_t pid; + + utarray_new(dirs,&ut_str_icd); + + while ( (opt = getopt(argc, argv, "v+f:d:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'f': file=optarg; read_conf(file); break; + case 'd': dir=optarg; utarray_push_back(dirs,&dir); break; + default: usage(argv[0]); break; + } + } + if (optind < argc) pub_transport = argv[optind++]; + if (!pub_transport) usage(argv[0]); + if ( (wn += utarray_len(dirs)) == 1) { + fprintf(stderr,"no directories configured\n"); + usage(argv[0]); + } + + if ( (workers = calloc(wn,sizeof(worker_t))) == NULL) exit(-1); + for(n=1; n 0) { + for(n=0; n < wn; n++) if (workers[n].pid==pid) break; + assert(n != wn); + int elapsed = time(NULL) - workers[n].start; + if (elapsed < SHORT_DELAY) defer_restart=1; + printf("pid %d exited after %d seconds: ", (int)pid, elapsed); + if (WIFEXITED(es)) printf("exit status %d\n", (int)WEXITSTATUS(es)); + else if (WIFSIGNALED(es)) printf("signal %d\n", (int)WTERMSIG(es)); + workers[n].pid = 0; + } + if (defer_restart) { + fprintf(stderr,"workers restarting too fast, delaying\n"); + alarm(SHORT_DELAY); + } + else run_workers(); + break; + case SIGALRM: + run_workers(); + break; + default: + printf("got signal %d\n", signo); + goto done; + break; + } + } + + done: + fini_workers(); + free(workers); + utarray_free(dirs); + return 0; +} diff --git a/utils/kvsp-reset.c b/utils/kvsp-reset.c new file mode 100644 index 0000000..643e44b --- /dev/null +++ b/utils/kvsp-reset.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "kvspool.h" + +char *dir; +char *base; +int verbose; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-b base] \n", exe); + exit(-1); +} + +int main(int argc, char *argv[]) { + + int opt; + char *exe = argv[0]; + while ( (opt = getopt(argc, argv, "b:v+")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'b': base=strdup(optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + else usage(exe); + + sp_reset(dir,base); + return 0; +} + diff --git a/utils/kvsp-size.c b/utils/kvsp-size.c new file mode 100644 index 0000000..65a0745 --- /dev/null +++ b/utils/kvsp-size.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utstring.h" + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] -s spool [ spool ... ]\n", prog); + fprintf(stderr, " is directory max size e.g. 1G (units KMGT)\n"); + fprintf(stderr, " Note: this command makes the limit persistent\n"); + exit(-1); +} + +int main(int argc, char * argv[]) { + int opt,verbose=0; + long dirmax=0; + /* input spool */ + char *dir=NULL,unit,*sz="10GB"; + UT_string *s; + utstring_new(s); + + while ( (opt = getopt(argc, argv, "v+s:")) != -1) { + switch (opt) { + default: usage(argv[0]); break; + case 'v': verbose++; break; + case 's': + sz = strdup(optarg); + switch (sscanf(sz, "%ld%c", &dirmax, &unit)) { + case 2: /* check unit */ + switch (unit) { + case 't': case 'T': break; + case 'g': case 'G': break; + case 'm': case 'M': break; + case 'k': case 'K': break; + case '\r': case '\n': case ' ': case '\t': break; + default: usage(argv[0]); break; + } + case 1: /* just a number in bytes */ break; + default: usage(argv[0]); break; + } + break; + } + } + if (optind >= argc) usage(argv[0]); + if (!dirmax) usage(argv[0]); + kv_spool_options.dir_max = dirmax; + + while (optind < argc) { + dir = argv[optind++]; + + utstring_clear(s); + utstring_printf(s,"%s/limits", dir); + char *p = utstring_body(s); + FILE *f = fopen(p, "w"); + if (f == NULL) { + fprintf(stderr,"cannot open %s: %s\n", p, strerror(errno)); + continue; + } + fprintf(f, "%s", sz); + fclose(f); + sp_attrition(dir); + } + + done: + utstring_free(s); + return 0; +} + diff --git a/utils/kvsp-speed.c b/utils/kvsp-speed.c new file mode 100644 index 0000000..3448889 --- /dev/null +++ b/utils/kvsp-speed.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include "kvspool.h" + +int frames=100000; +int verbose=0; +char *base = "spw"; +char *dir = "/tmp"; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-v] [-i iterations] []\n", exe); + exit(-1); +} + +struct timeval t1, t2; + +int main(int argc, char *argv[]) { + + long elapsed_usec_w, elapsed_usec_r; + int opt,i; + char *exe = argv[0]; + while ( (opt = getopt(argc, argv, "i:v+")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'i': frames=atoi(optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + char timebuf[100], iterbuf[10]; + time_t t = time(NULL); + snprintf(timebuf,sizeof(timebuf),"%s",ctime(&t)); + timebuf[strlen(timebuf)-1] = '\0'; /* trim \n */ + snprintf(iterbuf,sizeof(iterbuf),"%d",frames); + + void *set = kv_set_new(); + kv_adds(set, "from", exe); + kv_adds(set, "time", timebuf); + kv_adds(set, "iter", iterbuf); + + /* write test */ + gettimeofday(&t1,NULL); + for(i=0; i +#include +#include +#include "kvspool.h" +#include "utarray.h" +#include "utstring.h" + +int verbose=0; +char *base = NULL; +char *dir = NULL; +char *conf = NULL; +char *odir = "."; +int block=1; +unsigned n=2; +UT_array *keys; + +typedef struct { + char *base; + void *sp; + UT_hash_handle hh; +} osp_t; + +osp_t **ospv; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-v] [-b base] -n -k " + "[-k ...] [-o outdir] \n", exe); + exit(-1); +} + +void *get_output_spool(unsigned hv, char *base) { + osp_t *osp; + HASH_FIND_STR(ospv[hv%n],base,osp); + if (!osp) { + osp = malloc(sizeof(*osp)); if (!osp) goto done; + osp->base = strdup(base); + UT_string *suffixed_base; utstring_new(suffixed_base); + utstring_printf(suffixed_base, "%s-%u", base, (unsigned)(hv%n)); + osp->sp = kv_spoolwriter_new(odir,utstring_body(suffixed_base)); + utstring_free(suffixed_base); + if (osp->sp == NULL) { free(osp); return NULL;} + HASH_ADD_KEYPTR(hh,ospv[hv%n],osp->base,strlen(base),osp); + } + done: + return osp ? osp->sp : NULL; +} + +int main(int argc, char *argv[]) { + + kv_t *kv; + int opt,rc,i; + osp_t *osp, *tmp; + char *exe = argv[0]; + utarray_new(keys,&ut_str_icd); + + while ( (opt = getopt(argc, argv, "b:v+k:c:n:o:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'b': base=strdup(optarg); break; + case 'c': conf=strdup(optarg); break; + case 'o': odir=strdup(optarg); break; + case 'n': n=atoi(optarg); break; + case 'k': utarray_push_back(keys,&optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + else usage(exe); + + ospv = calloc(n, sizeof(void*)); + + void *sp = kv_spoolreader_new(dir,base); + if (!sp) exit(-1); + + void *set = kv_set_new(); + next_frame: + while ( (rc=kv_spool_read(sp,set,block)) > 0) { + /* calculate hash value of keys */ + unsigned hv=0, vlen=0; char *val, *key, **k=NULL; + while ( (k=(char**)utarray_next(keys,k))) { + key = *k; + kv = kv_get(set, key); + if (!kv) {printf("no such key: %s; skipping\n", key); goto next_frame;} + vlen = kv->vlen; val = kv->val; + while(vlen--) hv = hv * 33 + *val++; + } + char *sbase = kv_set_base(set); + osp = get_output_spool(hv,sbase); + if (kv_spool_write(osp, set) != 0) {printf("output error\n"); break; } + } + + /* clean up */ + for(i = 0; i < n; i++) { + HASH_ITER(hh,ospv[i],osp,tmp) { + HASH_DEL(ospv[i], osp); + free(osp->base); + kv_spoolwriter_free(osp->sp); + } + } + kv_spoolreader_free(sp); + kv_set_free(set); + utarray_free(keys); + return 0; +} diff --git a/utils/kvsp-spr.c b/utils/kvsp-spr.c new file mode 100644 index 0000000..feb2d4a --- /dev/null +++ b/utils/kvsp-spr.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "kvspool_internal.h" + +int block=1; +int verbose=0; +char *base = NULL; +char *dir = NULL; +enum {mode_out,mode_nop} mode = mode_out; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-c|-f] [-v] [-b base] [-B(lock) <1|0>] \n", exe); + fprintf(stderr," MODES: default (text mode)\n"); + fprintf(stderr," -f (discard mode)\n"); + exit(-1); +} + +/****************************************************************************** + * kvsp-spr: a spool reader, for manually inspecting contents of a spool + *****************************************************************************/ +int main(int argc, char *argv[]) { + + char *exe = argv[0]; + int opt; + + while ( (opt = getopt(argc, argv, "cfB:b:v+p:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'f': mode=mode_nop; break; + case 'b': base=strdup(optarg); break; + case 'B': block=atoi(optarg)?1:0; break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + else usage(exe); + + void *sp = kv_spoolreader_new(dir,base); + if (!sp) exit(-1); + + + void *set = kv_set_new(); + while (kv_spool_read(sp,set,block) > 0) { + switch(mode) { + case mode_nop: continue; + case mode_out: kv_set_dump(set,stdout); printf("\n"); break; + default: assert(0); break; + } + } + + done: + kv_spoolreader_free(sp); + kv_set_free(set); + return 0; +} diff --git a/utils/kvsp-spw.c b/utils/kvsp-spw.c new file mode 100644 index 0000000..87e76ec --- /dev/null +++ b/utils/kvsp-spw.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include "kvspool.h" + +int iterations=1; +int iter_delay=10; +int verbose=0; +char *base = "spw"; +char *dir = NULL; + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-v] [-f] [-b base] [-i iterations] [-d delay] \n", exe); + exit(-1); +} + +int main(int argc, char *argv[]) { + + int opt; + char *exe = argv[0]; + void *set; + + while ( (opt = getopt(argc, argv, "i:d:b:v+")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'i': iterations=atoi(optarg); break; + case 'd': iter_delay=atoi(optarg); break; + case 'b': base=strdup(optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) dir=argv[optind++]; + else usage(exe); + + void *sp = kv_spoolwriter_new(dir,base); + if (!sp) exit(-1); + + char timebuf[100], iterbuf[10]; + + while(iterations--) { + time_t t = time(NULL); + unsigned t32 = (unsigned)t; + snprintf(timebuf,sizeof(timebuf),"%s",ctime(&t)); + timebuf[strlen(timebuf)-1] = '\0'; /* trim \n */ + snprintf(iterbuf,sizeof(iterbuf),"%d",iterations); + + set = kv_set_new(); + kv_adds(set, "from", exe); + kv_adds(set, "when", timebuf); + /* add a binary value having the unix epoch time */ + kv_add(set, "time", strlen("time"), (char*)&t32, sizeof(t32)); + kv_adds(set, "iter", iterbuf); + kv_spool_write(sp,set); + kv_set_free(set); + if (iterations) sleep(iter_delay); + } + + kv_spoolwriter_free(sp); + return 0; +} + diff --git a/utils/kvsp-status.c b/utils/kvsp-status.c new file mode 100644 index 0000000..60349f7 --- /dev/null +++ b/utils/kvsp-status.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "kvspool_internal.h" +#include "utarray.h" + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] spool\n", prog); + exit(-1); +} + +int main(int argc, char * argv[]) { + int opt,verbose=0,fd=-1,sc,i; + char *dir=NULL, **f, *file; + UT_array *files; + utarray_new(files,&ut_str_icd); + struct stat sb; + uint32_t sz, spsz; + + while ( (opt = getopt(argc, argv, "v+")) != -1) { + switch (opt) { + case 'v': verbose++; break; + default: usage(argv[0]); break; + } + } + if (optind >= argc) usage(argv[0]); + dir = argv[optind++]; + + kv_stat_t *stats; + sc = kv_stat(dir,NULL,&stats); + if (sc == -1) { + printf("kv_stat error in %s\n", dir); + goto done; + } + for(i=0; i < sc; i++) { + printf("%-20s: %3u%%\n", stats[i].base, stats[i].pct_consumed); + } + if (stats) free(stats); + + /* the rest is for verbose output */ + if (!verbose) goto done; + printf("\n\n"); + if (sp_readdir(dir, "", ".sr", files) == -1) goto done; + f = NULL; + while ( (f=(char**)utarray_next(files,f))) { + file = *f; + printf("%s ",file); + if ( (fd=open(file,O_RDONLY)) == -1) { + perror("cannot open"); + goto done; + } + if (read(fd,&sz,sizeof(sz)) != sizeof(sz)) { + perror("cannot open"); + close(fd); + goto done; + } + close(fd); + file[strlen(file)-1]='p'; + if (stat(file,&sb) == -1) spsz = 0; + else spsz = sb.st_size; + /* ignore the spool preamble */ + if (spsz) spsz-=8; + sz -= 8; + printf("%u/%u (%2.2f%%)\n", sz, spsz, (spsz?(sz*100.0/spsz):0)); + } + + done: + utarray_free(files); + return 0; +} + diff --git a/utils/kvsp-sub.c b/utils/kvsp-sub.c new file mode 100644 index 0000000..21b5d47 --- /dev/null +++ b/utils/kvsp-sub.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include + +#include "kvspool_internal.h" +#include "utstring.h" +#include "uthash.h" + +typedef struct { /* helper that maps base --> spool handle */ + char *base; + void *sp; + UT_hash_handle hh; +} sp_t; + +int verbose=0; +char *dir; +char *file; +char *pub; + +void *context; +void *socket; +sp_t *spools; + + +void usage(char *exe) { + fprintf(stderr,"usage: %s [-v] [-f | -d ] \n", exe); + exit(-1); +} + +/* finds the spool handle for a given base, creating if necessary */ +void *get_spool(char *_base, size_t len) { + sp_t *spt; + + HASH_FIND(hh,spools,_base,len,spt); + if (spt) return spt->sp; + + spt = malloc(sizeof(*spt)); assert(spt); memset(spt,0,sizeof(*spt)); + spt->base = strndup(_base,len); + spt->sp = kv_spoolwriter_new(dir,spt->base); + if (!spt->sp) { free(spt->base); free(spt); return NULL; } + HASH_ADD_KEYPTR(hh,spools,spt->base,len,spt); + return spt->sp; +} + +void close_spools(void) { + sp_t *spt, *tmp; + HASH_ITER(hh,spools,spt,tmp) { + HASH_DEL(spools,spt); + free(spt->base); + kv_spoolwriter_free(spt->sp); + } +} + +int main(int argc, char *argv[]) { + + int64_t more; size_t more_sz = sizeof(more); + char *exe = argv[0], *filter = ""; + int part_num,opt,rc=-1; + void *msg_data, *sp; + size_t msg_len; + zmq_msg_t part; + + while ( (opt = getopt(argc, argv, "fd:v+")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'f': file=strdup(optarg); break; + case 'd': dir=strdup(optarg); break; + default: usage(exe); break; + } + } + if (optind < argc) pub=argv[optind++]; + if (!dir && !file) usage(exe); + if (!pub) usage(exe); + + if ( !(context = zmq_init(1))) goto done; + if ( !(socket = zmq_socket(context, ZMQ_SUB))) goto done; + if (zmq_connect(socket, pub)) goto done; + if (zmq_setsockopt(socket, ZMQ_SUBSCRIBE, filter, strlen(filter))) goto done; + + while(1) { + + /* receive a multi-part message */ + part_num=1; + do { + if ( (rc= zmq_msg_init(&part))) goto done; + if ( ((rc= zmq_recv(socket, &part, 0)) != 0) || + ((rc= zmq_getsockopt(socket, ZMQ_RCVMORE, &more,&more_sz)) != 0)) { + zmq_msg_close(&part); + goto done; + } + + msg_data = zmq_msg_data(&part); + msg_len = zmq_msg_size(&part); + + switch(part_num) { /* part 1 has the base; part 2 has serialized frame */ + case 1: sp=get_spool(msg_data,msg_len); break; + case 2: if (kv_write_raw_frame(sp,msg_data,msg_len)) goto done; break; + default: assert(0); + } + + zmq_msg_close(&part); + part_num++; + } while(more); + } + rc = 0; /* not reached TODO under clean shutdown on signal */ + + + done: + if (rc) fprintf(stderr,"%s: %s\n", exe, zmq_strerror(errno)); + if(socket) zmq_close(socket); + if(context) zmq_term(context); + close_spools(); + return rc; +} + diff --git a/utils/kvsp-tee.c b/utils/kvsp-tee.c new file mode 100644 index 0000000..7d05533 --- /dev/null +++ b/utils/kvsp-tee.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "utarray.h" + +typedef struct { + char *base; + void *sp; +} ospool_base_t; + +typedef struct { + char *dir; + UT_array /* of ospool_base_t */ basev; +} ospool_t; + +/* plumbing for ospool_base_t array */ +void ospool_base_ini(void *_ospb) { + ospool_base_t *ospb = (ospool_base_t*)_ospb; + ospb->base=NULL; + ospb->sp=NULL; +} +void ospool_base_cpy(void *_dst, const void *_src) { + ospool_base_t *dst = (ospool_base_t*)_dst; + ospool_base_t *src = (ospool_base_t*)_src; + dst->base = src->base ? strdup(src->base) : NULL; + dst->sp = src->sp; +} +void ospool_base_fin(void *_ospb) { + ospool_base_t *ospb = (ospool_base_t*)_ospb; + if (ospb->base) free(ospb->base); + /* we don't release osbp->sp because its shared */ +} + +UT_icd ospool_base_icd = {sizeof(ospool_base_t),ospool_base_ini,ospool_base_cpy,ospool_base_fin}; + +/* plumbing for ospool_t array */ +void ospool_ini(void *_osp) { + ospool_t *osp = (ospool_t*)_osp; + osp->dir = NULL; + utarray_init(&osp->basev, &ospool_base_icd); +} +void ospool_cpy(void *_dst, const void *_src) { + ospool_t *dst = (ospool_t*)_dst; + ospool_t *src = (ospool_t*)_src; + dst->dir = src->dir ? strdup(src->dir) : NULL; + utarray_init(&dst->basev, &ospool_base_icd); + utarray_concat(&dst->basev, &src->basev); +} +void ospool_fin(void *_osp) { + ospool_t *osp = (ospool_t*)_osp; + if (osp->dir) free(osp->dir); + utarray_done(&osp->basev); +} + +UT_icd ospool_icd = {sizeof(ospool_t),ospool_ini,ospool_cpy,ospool_fin}; + + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] -s spool [-d base] ...\n", prog); + exit(-1); +} + +int main(int argc, char * argv[]) { + int opt,verbose=0,dirmax=0,filemax=0; + ospool_t *osp; + void *set; + /* input spool */ + char *dir=NULL; + char *base=NULL; + void *sp; + + set = kv_set_new(); + UT_array *ospoolv; + utarray_new(ospoolv, &ospool_icd); + + while ( (opt = getopt(argc, argv, "v+D:F:b:s:")) != -1) { + switch (opt) { + case 'v': verbose++; break; + case 'D': dirmax = atoi(optarg); if (dirmax==0) usage(argv[0]); break; + case 'F': filemax = atoi(optarg); if (filemax==0) usage(argv[0]); break; + case 'b': base = strdup(optarg); break; + case 's': dir = strdup(optarg); break; + default: usage(argv[0]); break; + } + } + if (dir==NULL) usage(argv[0]); + sp = kv_spoolreader_new(dir,base); + if (sp == NULL) { + fprintf(stderr, "failed to open input spool %s\n", dir); + goto done; + } + + while (optind < argc) { + utarray_extend_back(ospoolv); + osp = (ospool_t*)utarray_back(ospoolv); + osp->dir = strdup(argv[optind++]); + } + + while (kv_spool_read(sp,set,1) == 1) { + osp=NULL; + while ( (osp=(ospool_t*)utarray_next(ospoolv,osp))) { + /* do we already have a spool handle for this base? */ + char *base = kv_set_base(set); + ospool_base_t *ospb=NULL; + while ( (ospb=(ospool_base_t*)utarray_next(&osp->basev,ospb))) { + if (strcmp(ospb->base,base)) continue; + break; /* found an open spool handle */ + } + if (ospb==NULL) { /* didn't have a spool handle for base? */ + utarray_extend_back(&osp->basev); + ospb = (ospool_base_t*)utarray_back(&osp->basev); + ospb->base = strdup(base); + ospb->sp = kv_spoolwriter_new(osp->dir,ospb->base); + if (!ospb->sp) { + fprintf(stderr, "failed to open output spool %s base %s\n",dir,base); + goto done; + } + } + kv_spool_write(ospb->sp,set); + } + } + + done: + kv_set_free(set); + osp=NULL; + /* deep free the spoolwriter handles */ + while ( (osp=(ospool_t*)utarray_next(ospoolv,osp))) { + ospool_base_t *ospb=NULL; + while ( (ospb=(ospool_base_t*)utarray_next(&osp->basev,ospb))) { + kv_spoolwriter_free(ospb->sp); + } + } + utarray_free(ospoolv); + return 0; +} + diff --git a/utils/ts/Makefile b/utils/ts/Makefile new file mode 100644 index 0000000..bc7940e --- /dev/null +++ b/utils/ts/Makefile @@ -0,0 +1,12 @@ +all: libts.a +CFLAGS=-g + +ts.o: ts.c ts.h + +libts.a: ts.o + ar cr $@ $^ + +.PHONY: clean + +clean: + rm -f *.o libts.a diff --git a/utils/ts/tests/Makefile b/utils/ts/tests/Makefile new file mode 100644 index 0000000..5ee6473 --- /dev/null +++ b/utils/ts/tests/Makefile @@ -0,0 +1,27 @@ +SRCS = $(wildcard test*.c) +PROGS = $(patsubst %.c,%,$(SRCS)) + +LIBDIR = .. +LIB = $(LIBDIR)/libts.a + +CFLAGS = -I$(LIBDIR) -fno-strict-aliasing +CFLAGS += -g +CFLAGS += -Wall +CFLAGS += ${EXTRA_CFLAGS} + +TEST_TARGET=run_tests +TESTS=./do_tests + +all: $(PROGS) $(TEST_TARGET) + +$(PROGS): $(LIB) + $(CC) $(CFLAGS) -o $@ $(@).c $(LIB) + +run_tests: $(PROGS) + perl $(TESTS) + +.PHONY: clean + +clean: + rm -f $(PROGS) test*.out + rm -rf *.dSYM diff --git a/utils/ts/tests/do_tests b/utils/ts/tests/do_tests new file mode 100755 index 0000000..574403f --- /dev/null +++ b/utils/ts/tests/do_tests @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/utils/ts/tests/test1.ans b/utils/ts/tests/test1.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/utils/ts/tests/test1.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/utils/ts/tests/test1.c b/utils/ts/tests/test1.c new file mode 100644 index 0000000..6f3c379 --- /dev/null +++ b/utils/ts/tests/test1.c @@ -0,0 +1,22 @@ +#include +#include +#include "ts.h" + +void insert(long *cur, long *incr) { *cur += *incr; } +void show(long *i) { printf("%lu\n", *i); } + +const ts_mm mm = {.sz=sizeof(long), + .data=(data_f*)insert, + .show=(show_f*)show }; +int main() { + time_t i=0; + long one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/utils/ts/tests/test2.ans b/utils/ts/tests/test2.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/utils/ts/tests/test2.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/utils/ts/tests/test2.c b/utils/ts/tests/test2.c new file mode 100644 index 0000000..f837263 --- /dev/null +++ b/utils/ts/tests/test2.c @@ -0,0 +1,22 @@ +#include +#include +#include "ts.h" + +void insert(char *cur, char *incr) { *cur += *incr; } +void show(char *i) { printf("%u\n", (unsigned)*i); } + +const ts_mm mm = {.sz=sizeof(char), + .data=(data_f*)insert, + .show=(show_f*)show }; +int main() { + time_t i=0; + char one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/utils/ts/tests/test3.ans b/utils/ts/tests/test3.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/utils/ts/tests/test3.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/utils/ts/tests/test3.c b/utils/ts/tests/test3.c new file mode 100644 index 0000000..5a10cc4 --- /dev/null +++ b/utils/ts/tests/test3.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "ts.h" + +void insert(uint16_t *cur, uint16_t *incr) { *cur += *incr; } +void show(uint16_t *i) { printf("%u\n", (unsigned)*i); } + +const ts_mm mm = {.sz=sizeof(uint16_t), + .data=(data_f*)insert, + .show=(show_f*)show }; +int main() { + time_t i=0; + uint16_t one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/utils/ts/tests/test4.ans b/utils/ts/tests/test4.ans new file mode 100644 index 0000000..d331ca4 --- /dev/null +++ b/utils/ts/tests/test4.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 4 +#1(565): 0 +#2(575): 1 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/utils/ts/tests/test4.c b/utils/ts/tests/test4.c new file mode 100644 index 0000000..2a6b584 --- /dev/null +++ b/utils/ts/tests/test4.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "ts.h" + +typedef struct { + char c[7]; +} seven_t; + +void insert(seven_t *cur, seven_t *incr) { cur->c[0]++; } +void show(seven_t *i) { printf("%u\n", (unsigned)(i->c[0])); } + +const ts_mm mm = {.sz=sizeof(seven_t), + .data=(data_f*)insert, + .show=(show_f*)show }; +int main() { + time_t i=0; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, NULL); ts_show(t); + ts_add(t,100,NULL); ts_show(t); + ts_add(t,120,NULL); ts_show(t); + ts_add(t,555,NULL); //ts_show(t); + ts_add(t,555,NULL); //ts_show(t); + ts_add(t,556,NULL); //ts_show(t); + ts_add(t,564,NULL); //ts_show(t); + ts_add(t,575,NULL); ts_show(t); + ts_free(t); + return 0; +} diff --git a/utils/ts/tests/test5.ans b/utils/ts/tests/test5.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/utils/ts/tests/test5.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/utils/ts/tests/test5.c b/utils/ts/tests/test5.c new file mode 100644 index 0000000..69c39e0 --- /dev/null +++ b/utils/ts/tests/test5.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "ts.h" + +void insert(uint64_t *cur, uint64_t *incr) { *cur += *incr; } +void show(uint64_t *i) { printf("%lu\n", (long)*i); } + +const ts_mm mm = {.sz=sizeof(uint64_t), + .data=(data_f*)insert, + .show=(show_f*)show }; +int main() { + time_t i=0; + uint64_t one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/utils/ts/ts.c b/utils/ts/ts.c new file mode 100644 index 0000000..43f4854 --- /dev/null +++ b/utils/ts/ts.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include "ts.h" + +static void ts_clear(char *data, size_t sz) { memset(data,0,sz); } +#define bkt(t,i) ((ts_bucket*)((char*)((t)->buckets) + ((i)*(sizeof(ts_bucket)+(t)->mm.sz)))) + +ts_t *ts_new(unsigned num_buckets, unsigned secs_per_bucket, const ts_mm *mm) { + int i; + ts_t *t = calloc(1,sizeof(ts_t)); if (!t) return NULL; + t->secs_per_bucket = secs_per_bucket; + t->num_buckets = num_buckets; + t->mm = *mm; /* struct copy */ + // pad sz so sequential buckets' time_t are naturally aligned + int pad = ((t->mm.sz % sizeof(ts_bucket)) > 0) ? + (sizeof(ts_bucket) - (t->mm.sz % sizeof(ts_bucket))) : + 0; + t->mm.sz += pad; + if (t->mm.ctor == NULL) t->mm.ctor = (ctor_f*)ts_clear; + t->buckets = calloc(num_buckets,sizeof(ts_bucket)+t->mm.sz); + if (t->buckets == NULL) { free(t); return NULL; } + for(i=0; inum_buckets; i++) { + //fprintf(stderr,"t->buckets %p bkt(t,%d) %p\n", t->buckets, i, bkt(t,i)); + bkt(t,i)->start = i * t->secs_per_bucket; + t->mm.ctor(bkt(t,i)->data,t->mm.sz); + } + return t; +} + +void ts_add(ts_t *t, time_t when, void *data) { + int i; + /* figure out bucket it should go in */ + unsigned idx = (when - bkt(t,0)->start) / t->secs_per_bucket; + if (idx >= t->num_buckets) { // shift + unsigned shift = (idx - t->num_buckets) + 1; + if (shift > t->num_buckets) shift = t->num_buckets; + if (shift <= t->num_buckets) { + if (t->mm.dtor) { + for(i=0; imm.dtor(bkt(t,i)->data); + } + } + if (shift < t->num_buckets) { + memmove(bkt(t,0),bkt(t,shift),(t->num_buckets-shift)*(sizeof(ts_bucket)+t->mm.sz)); + } + if (shift) { + for(i=t->num_buckets-shift; inum_buckets; i++) { + t->mm.ctor(bkt(t,i)->data,t->mm.sz); + bkt(t,i)->start = (i > 0) ? (bkt(t,i-1)->start + t->secs_per_bucket) : when; + } + } + idx = (when - bkt(t,0)->start) / t->secs_per_bucket; + assert(idx < t->num_buckets); + } + void *cur = bkt(t,idx)->data; + t->mm.data(cur,data); +} + +void ts_free(ts_t *t) { + int i; + if (t->mm.dtor) { + for(i=0; inum_buckets; i++) t->mm.dtor(bkt(t,i)->data); + } + free(t->buckets); + free(t); +} + +void ts_show(ts_t *t) { + int i; + for(i=0; inum_buckets; i++) { + printf("#%d(%lu): ", i, (long)(bkt(t,i)->start)); + if (t->mm.show) t->mm.show(bkt(t,i)->data); + else printf("\n"); + } + printf("\n"); +} diff --git a/utils/ts/ts.h b/utils/ts/ts.h new file mode 100644 index 0000000..afd51e9 --- /dev/null +++ b/utils/ts/ts.h @@ -0,0 +1,30 @@ + +typedef void (data_f)(char *cur, char *add); +typedef void (ctor_f)(void *elt, size_t sz); +typedef void (dtor_f)(void *elt); +typedef void (show_f)(void *elt); +typedef struct { + size_t sz; + data_f *data; + ctor_f *ctor; + dtor_f *dtor; + show_f *show; +} ts_mm; + +typedef struct { + time_t start; + char data[]; /* C99 flexible array member */ +} ts_bucket; + +typedef struct { + ts_mm mm; + unsigned secs_per_bucket; + unsigned num_buckets; + ts_bucket *buckets; +} ts_t; + +ts_t *ts_new(unsigned num_buckets, unsigned secs_per_bucket, const ts_mm *mm); +void ts_add(ts_t *t, time_t when, void *data); +void ts_free(ts_t *t); +void ts_show(ts_t *t); + diff --git a/utils/ts/ts.o b/utils/ts/ts.o new file mode 100644 index 0000000000000000000000000000000000000000..ab776fef71d290bb2e5bcaa4ca57d71418b43bfb GIT binary patch literal 9080 zcmbVRdu&_P89(YV&=gublu`l>G*H~$(g#^dM%%3z+i?=Bi5>h% zN=IqIFlMZ7guw)RsAv0gDculMTD4WElUg-GUC{t-ld|u39`?)d!Fw+?zzr^(3TCRVKCJUb{8vi3T14fp-gvivWqpdCe~{g{$b~*ymn## zmv$j{#V+>JU+Bv>p<@?LUqt`jNvJ(QdToXM=L)&AcAET6pW=J5)li$drv67`a8oZxJMJR)9~m+W&3-au+X z&@Cm*KGba$L+9+mM{2xwK^k|rOY3%6FA|2LCSs6>$ldAC6ue$e3*GMaVra^ay(>6o z=Z{%-{jZM8go<_>iHR>9vkRus!KjfVCDu#buJ&RtIk+mgg?9b~9DHOSYV>isaLO)x zJbfk~nlhk>5_he*{Y3g8_mY3R?VIKK+ClUBF3l?i>zyDuWz|JvLL`FD*vpRtEOxaa zozM}x@V;G`w2%LLo&ClBBch}vU9mQFvHqD_la~&BvG-!(%<|)fck{=LLg<3}KNcUatStf2=#6W#(Vc04Zv4QT5{5ki&xI3;C@DGSN`vBCKQ zq@x4dZ2F9ye|v{xp|;UNg)aSd@l~?bxk?D-tAu*TDj`mVtguS>);P=Skp8{&O!F*u zFXt6KbIb5dWbjMR(qM(HW8xff#ZZf0ei{_FPVr^L8C4=u?($>Vua+=?;PKiNlfTb5HjvGI)tqqWXghg#lw-tuor=E1UUN&(LeUfk$X^ zs+W})k#gN8-|AYpyrzaKw2)p+%|J!+z!xLQAPxQ6*-mH*K6OzYsi%tYw<~{ezQThm znt$mak<0Qxp{mNANM?z1gHxS>7Z`JyT*Xx-I)i2mAlGzT9`4Nb;syfeSsn{79GB4H zlBzBHfQT?0ahty;#4=9MbN(~xA+mS7{>Wv21N<}|E9oI+RhNjgjDG=!Ou}x!)ot#1 z+i1`=nSIRdfsxt5YN6z|fSWCr;O6&m&MUa;U7TwcT+PFr^D~e28d-WQr0B7bjK@M) zk$){NFx8g3?uXP1%la1}RS~@qP(-!>)p(Vdx-lZ8dBY$uvtd|77H!rC0~_KigP zn9(34J7@%-Q&^AnCP{e#nnV`asW9j zQ8^^~_A;X-$}`%rh&uKdc{AqILo{D3mu5x>jLmWT8U?Gq8HCX)9Q4q^fmwx%#hBH3 ztP#n{>^m!Ff0PuEeWxgejr8u6>9K3YxI+~!VHI*%ZBSOMn)FTfeWYgmr)~i~`7N7J zBbdvigF}gEa3B^7?(J9;UbA}TP$HSzyK*3z3$6~V4%`w+keAP-=?dDS7;lpO2 z@fGuWpS9B(C*ExFJ#Vh^nVt1k>*i5wt9gs>GZO7Q`kuM5>8QE6@vybT?DUy2ueFM5U-YHpINoUMb^i5^V ztLTqqP?OE}rDSJII%Afi|60bpiasb4tmI3{o+#;zS&DwDjCmDZ?H0*a@}*=oC7m%# z(RF3atLVuRHhYYn6hLW=zE_0g`a8giK;zJe*~H*;G2*PYXJd&axOW2q0DqC>}Nwk7dFm@w5X+X5n!6 z_E1mH&hUobZR>kB-M=jyW_^)tgz@}x$xLD(8SnGQ1|w-626#H_FA4CDmE#SEv2`e& zp;U4}(-4B-U}`uX%nnA9nN%_u8;r;Hq;lCzFqVkX=BC{o+%uXPNu`E@xol!66Qs2+ z!Xe6xkjRck%p=VXhXKrx!hYknUjKSOKPq^QNI`8V8UP*lV}tP|#Y^<_5y@e|k`JDA zcuAZEAuKi&r^<*UW#jtwclg_Sqq$@@CjzZpo#WiC%Vl89VWXT#W8ZdW?DZPg)q1Sw zXfxnY{+g8WO?Y>mcl~$F1-P9+hRY2a-i=JjcII8Mp);JfUt%RHnc0)4wZ?6;Ld>2; zujJpzyWsaZDLdtq^^$2I^XPCk5~V(y7X6^2(($24ARFJCWdXig0?|x{$apk25ROEn z>G&uMa2)|9lKrU}0L^xsfRr#6N<*pG44si&G#MF=lV69YNIH@n048iG9~OwEhKJ)c zPl04A8xPPtucVz2+avAbgR}w2j~wM!@BCzn(qlfHtxGcchE<2H(!Gud9fR!3wL;^d zJP`3d2dRz&%n{lR^amVs>TLMnsMPdWIB4MWtJ>d8wlc*T;Z*zwHKE3`d*`qp@CbJ} zKAlas$2~zG6ZA*qrfHXTK>a}K_3I@}_el`jNuMBSb(&CPSvToaivP;>+??+-P>7G% zdi)4s@QE$zYyb@6BUq1)pOsWkqH z3gbsg`uM*`nC=tN?w9e~!8n?(TOe7b_>(fevPb>lQjh;r!r)Ws5y{&D8UJN1pkh^j zgtRN!H+zMjrJ^f6m7VJGji~675)qx!-id+Mbx%o5Uq4;a9{D+&8o$Dh6H%#ttVL+- zm5Qhz{Z25ee)u_C+oIg!qKrSux$;BLAH1GBv?t`}2|l*az%HaemA^Xw<`Y&a{)jw3 zA1Ar9>G7R1Ck?$S_Rnc2rfAo!Sr8Ie#Y~W2#R?NHZ;;Bd>|L|oCd$7Wec1qKn(4?# zUDToBV)TQG*6{so5Z)?rdCYRo#pI!<*|@|PyN1HQ+$5UBB|f4x6#AIK+0DgQRwW#( zYi4UBw$j!J626c|rpC|jLxioFL;ub>@Oz{m^^wBwPK0fmL;ve@;9=?KpqzSs$0BS% z;_71q`xh-mf0f2HItMOpm!-RAg&TWdRmaU8Y&brgiI;BUvB(fERQ&Ewwz%t)!fdC>)-0Yn@Cgnsgs)>`ZyC5-XiM^|2PxW`d+EwB;swAhO3=;o5bNC zXN>aynFDv`Gd%}xONS~Sc^t7_5{G}>{gnS#9XPHo3V&w~9Qz&({-p}%*O`K{IPpGhA33{B;e zka>0sxP;#*@dq`0Nb(P9_yNhsHT+A-D?1hUfb^fy^gosSw>A7_$v>yz`0p#)i=r## z|69qcajUqsQvVm4ev8CUYWTep|GS3cU5)m+=t^PVq5?A@CxF2e`djFks_(47|Nk3N|IP%#Ehtv#t&a3)I1L z@NE*mRpKyrp8s1MI6?(wydDi-E6?%Wn*WDnKKw@$vRC=wzJd0v=0}b9c@0Ky*i;RpWPrJtY3IACQ7IO2SdC>jDqW4ww6uI?zh hA3ucD;M?iHlcQx^?TZ~6uGY_94OjJiLBmx&{|7brD>eWC literal 0 HcmV?d00001 diff --git a/utstring.h b/utstring.h new file mode 100644 index 0000000..2379662 --- /dev/null +++ b/utstring.h @@ -0,0 +1,148 @@ +/* +Copyright (c) 2008-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + * see http://uthash.sourceforge.net/utstring + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 1.9.4 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include +#include +#include +#define oom() exit(-1) + +typedef struct { + char *d; + size_t n; /* allocd size */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ + if ((s)->d == NULL) oom(); \ + (s)->n += amt; \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + s = (UT_string*)calloc(sizeof(UT_string),1); \ + if (!s) oom(); \ + utstring_init(s); \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve((s),(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + (s)->i += l; \ + (s)->d[(s)->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve(dst,(src->i)+1); \ + if (src->i) memcpy(&(dst)->d[(dst)->i], src->d, src->i); \ + dst->i += src->i; \ + dst->d[dst->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((unsigned)((s)->i)) + +#define utstring_body(s) ((s)->d) + +_UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + while (1) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && (n < (int)(s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +_UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +#endif /* UTSTRING_H */ diff --git a/zmq_app/Makefile b/zmq_app/Makefile new file mode 100644 index 0000000..9725f90 --- /dev/null +++ b/zmq_app/Makefile @@ -0,0 +1,27 @@ +OBJS=libts.a libzcontrol.a kvz zcon +all: $(OBJS) +CFLAGS= -I. -I.. +#CFLAGS+=-O2 +CFLAGS+=-g + +ts.o: ts.c ts.h + +libts.a: ts.o + ar cr $@ $^ + +libzcontrol.a: zcontrol.o + ar cr $@ $^ + +zcon: zcon.c + $(CC) $(CFLAGS) -c $< + $(CC) $(CFLAGS) -o $@ $< -lzmq -lreadline + +kvz: kvz.c kvz_cmds.c libts.a libzcontrol.a + $(CC) $(CFLAGS) -pthread -c kvz.c + $(CC) $(CFLAGS) -pthread -c kvz_cmds.c + $(CC) $(CFLAGS) -pthread -o kvz kvz.o kvz_cmds.o -lzmq -lkvspool -L. -lts -lzcontrol + +.PHONY: clean + +clean: + rm -f *.o $(OBJS) diff --git a/zmq_app/README b/zmq_app/README new file mode 100644 index 0000000..cc8f26e --- /dev/null +++ b/zmq_app/README @@ -0,0 +1,13 @@ +kvz is a sample or template application which consumes a spool +but does not have any application specific logic (that is why +it is a template - you're supposed to fill in application logic). + +kvz is a C program that implements a ZeroMQ based main loop, which +polls on ZeroMQ messages from either the spool reader thread or +the control port thread. Thus, it can be connected to using +zcon and tested interactively using the 'help' commands etc. + +A real application would fill in logic in the zmq_poll section +to handle the specific application's spool data and would add new +application-specific commands to kvz_cmds.c. + diff --git a/zmq_app/example/Makefile b/zmq_app/example/Makefile new file mode 100644 index 0000000..42c02a1 --- /dev/null +++ b/zmq_app/example/Makefile @@ -0,0 +1,21 @@ +OBJS=libtracker.a kvzuri +all: $(OBJS) +CFLAGS= -I. -I.. -I../.. +#CFLAGS+=-O2 +CFLAGS+=-g + +tracker.o: tracker.c tracker.h + $(CC) $(CFLAGS) -c $< + +libtracker.a: tracker.o + ar cr $@ $^ + +kvzuri: kvzuri.c kvzuri_cmds.c ../libts.a libtracker.a ../libzcontrol.a + $(CC) $(CFLAGS) -pthread -c kvzuri.c + $(CC) $(CFLAGS) -pthread -c kvzuri_cmds.c + $(CC) $(CFLAGS) -pthread -o kvzuri kvzuri.o kvzuri_cmds.o -lzmq -lkvspool -L.. -lts -lzcontrol -L. -ltracker + +.PHONY: clean + +clean: + rm -f *.o $(OBJS) diff --git a/zmq_app/example/kvzuri.c b/zmq_app/example/kvzuri.c new file mode 100644 index 0000000..ea2b4db --- /dev/null +++ b/zmq_app/example/kvzuri.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "zcontrol.h" +#include "utarray.h" +#include "kvzuri.h" + +struct _CF CF = { + .zcontrol_endpoint = ZCON_DEF_ENDPOINT, +}; + +extern cp_cmd_t cmds[]; + +static void s_signal_handler (int signal_value) { + CF.request_exit = 1; +} + +static void s_catch_signals (void) { + struct sigaction action; + action.sa_handler = s_signal_handler; + action.sa_flags = 0; + sigemptyset (&action.sa_mask); + sigaction (SIGINT, &action, NULL); + sigaction (SIGTERM, &action, NULL); +} + +static unsigned hash_ber(char *in) { + unsigned hashv = 0; + while (*in != '\0') hashv = ((hashv) * 33) + *in++; + return hashv; +} + +#define bucket(u) (u & ((1 << LN_URI_BUCKETS) - 1)) +static void uri_hash_incr(int *urimap, char *uri) { + unsigned uri_hash = hash_ber(uri); + urimap[bucket(uri_hash)]++; +} +// want to use renew here (no dtor) but then there's no way to do a final 'done' since dtor is on every ts slide +static void etop_ctor(UT_array *a, size_t sz) {utarray_init(a,&ut_int_icd);} +static void etop_dtor(UT_array *a) {utarray_done(a);} +static int intcmp(const void *_a, const void *_b) {int a=*(int *)_a; int b=*(int*)_b; return a-b;} +#define MAX_DAILY_URI_PER_IP 1000 +static void etop_add(UT_array *a, char *uri) { + // add uniquely; if not found; add, sort + if (utarray_len(a) >= MAX_DAILY_URI_PER_IP) return; + int uri_hash = hash_ber(uri); + if (utarray_find(a,&uri_hash,intcmp)) return; + utarray_push_back(a,&uri_hash); + utarray_sort(a,intcmp); +} +ts_mm hits_1h_mm = {.sz=sizeof(int)}; +ts_mm hits_1w_mm = {.sz=sizeof(int)}; +ts_mm maps_1h_mm = {.sz=sizeof(int)*URI_BUCKETS,.data=(ts_data_f*)uri_hash_incr}; +ts_mm etop_1w_mm = {.sz=sizeof(UT_array),.data=(ts_data_f*)etop_add,.ctor=(ts_ctor_f*)etop_ctor,.dtor=(ts_dtor_f*)etop_dtor}; + +kvz_t *new_kvz(void) { + kvz_t *c = malloc(sizeof(kvz_t)); + memset(c,0,sizeof(*c)); + c->hits_1h = ts_new(60/5,5*60,&hits_1h_mm); + c->maps_1h = ts_new(60,60,&maps_1h_mm); + c->hits_1w = ts_new(24*7,60*60,&hits_1w_mm); + c->uri_tracker = tracker_new(100000,10); + return c; +} + +void free_kvz(kvz_t *c) { + user_t *u, *tmp; + HASH_ITER(hh, c->users, u, tmp) { + HASH_DEL(c->users, u); + ts_free(u->hits_1h); + ts_free(u->maps_1h); + ts_free(u->hits_1w); + ts_free(u->etop_1w); + free(u); + } + ts_free(c->hits_1h); + ts_free(c->maps_1h); + ts_free(c->hits_1w); + tracker_free(c->uri_tracker); + free(c); +} + +void add_hit(kvz_t *c, char *ip, char *when, char *uri) { + user_t user,*u; + time_t t = atol(when); + HASH_FIND(hh, c->users, ip, strlen(ip), u); + if (!u) { + u = calloc(1,sizeof(user_t)); + if (!u) {fprintf(stderr,"oom\n"); return;} + strncpy(u->ip, ip, sizeof(u->ip)); + u->hits_1h = ts_new(60/5,5*60,&hits_1h_mm); + u->maps_1h = ts_new(60,60,&maps_1h_mm); + u->hits_1w = ts_new(24*7,60*60,&hits_1w_mm); + u->etop_1w = ts_new(7,24*60*60,&etop_1w_mm); + u->last = t; + HASH_ADD(hh, c->users, ip, strlen(ip), u); + } + ts_add(u->hits_1h, t, NULL); + ts_add(u->maps_1h, t, uri); + ts_add(u->hits_1w, t, NULL); + ts_add(u->etop_1w, t, uri); + // enterprise + ts_add(c->hits_1h, t, NULL); + ts_add(c->maps_1h, t, uri); + ts_add(c->hits_1w, t, NULL); + tracker_hit(c->uri_tracker, uri, t); + c->last = t; +} + +void show_version(char *prog) { + fprintf(stderr, "%s 0.1\n", prog); + int major, minor, patch; + zmq_version (&major, &minor, &patch); + fprintf(stderr,"Current 0MQ version is %d.%d.%d\n", major, minor, patch); + exit(-1); +} + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-s spool] [-x] [-w] [-V]\n", prog); + exit(-1); +} + +// this is for development when reading a historical web spool +// it adds delays as needed to read at the original event rate +time_t last_frame_ts, last_frame_wc; +void walltime_delay(void *set) { + time_t cur_frame_ts, now=time(NULL); + kv_t *ts = kv_get(set,"ts"); if (!ts) return; + cur_frame_ts = atol(ts->val); + if (last_frame_ts==0) last_frame_ts=cur_frame_ts; + if (last_frame_wc==0) last_frame_wc=now; + time_t frame_elapsed = (cur_frame_ts-last_frame_ts); + time_t wallt_elapsed = (now-last_frame_wc); + if (frame_elapsed > wallt_elapsed) { + time_t delay = frame_elapsed-wallt_elapsed; + //fprintf(stderr,"delaying %lu\n",(long)delay); + sleep(delay); + } + last_frame_ts = cur_frame_ts; + last_frame_wc = now; +} + +// this function runs in a separate thread that pushes to main thread +static void* spr(void *data) { + void *sp=NULL; + int rc=-1, block=!CF.exit_when_spool_consumed; + + if ( (sp = kv_spoolreader_new(CF.spool,NULL)) == NULL) { + fprintf(stderr, "failed to open %s\n", CF.spool); + goto abnormal_exit; + } + + zmq_msg_t msg; + void *set; + while(CF.request_exit==0) { + set = kv_set_new(); + if (kv_spool_read(sp, set, block) != 1) break; + if (CF.walltime_mode) walltime_delay(set); + if (zmq_msg_init_size(&msg, sizeof(void*))) break; + memcpy(zmq_msg_data(&msg), &set, sizeof(void*)); + if (zmq_send(CF.spr_push_socket, &msg, 0)) break; + if (zmq_msg_close(&msg)) break; + CF.frames_read++; + } + + abnormal_exit: + if (sp) kv_spoolreader_free(sp); + fprintf(stderr, "spool reader exiting\n"); + CF.request_exit=1; + // kick the main loop to fall out of msg-recv and honor exit request */ + zmq_msg_init_size(&msg, 0); + zmq_send(CF.spr_push_socket, &msg, 0); + zmq_msg_close(&msg); + return NULL; +} + +int setup_zmq() { + int zero=0; uint64_t one=1; + if (( (CF.zmq_context = zmq_init(1)) == NULL) || + ( (CF.spr_push_socket = zmq_socket(CF.zmq_context, ZMQ_PUSH)) == NULL) || + ( (CF.spr_pull_socket = zmq_socket(CF.zmq_context, ZMQ_PULL)) == NULL) || + ( (CF.zcontrol_socket = zmq_socket(CF.zmq_context, ZMQ_REP )) == NULL) || + ( zmq_setsockopt(CF.spr_push_socket, ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_setsockopt(CF.spr_pull_socket, ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_setsockopt(CF.spr_push_socket, ZMQ_HWM, &one, sizeof(one))) || + ( zmq_setsockopt(CF.zcontrol_socket , ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_bind(CF.zcontrol_socket, CF.zcontrol_endpoint ) != 0) || + ( zmq_bind( CF.spr_push_socket, "inproc://spr") != 0) || + ( zmq_connect(CF.spr_pull_socket, "inproc://spr") != 0)) { + fprintf(stderr,"zeromq setup failed: %s\n", zmq_strerror(errno)); + return -1; + } + return 0; +} + +void msg_loop() { + + zmq_pollitem_t items [] = { + { CF.spr_pull_socket, 0, ZMQ_POLLIN, 0 }, + { CF.zcontrol_socket, 0, ZMQ_POLLIN, 0 }, + }; + + while (CF.request_exit==0) { + zmq_msg_t msg; + zmq_poll (items, adim(items), -1); + + if (items[0].revents & ZMQ_POLLIN) { // spool reader socket + zmq_msg_init (&msg); + if (zmq_recv(CF.spr_pull_socket, &msg, 0)) { + fprintf(stderr,"zmq_recv: %s\n", zmq_strerror(errno)); break; + } + void **_set = zmq_msg_data(&msg); void *set = *_set; + if (zmq_msg_size(&msg) == sizeof(void*)) { + kv_t *sip = kv_get(set, "sip"); + kv_t *when = kv_get(set, "ts"); + kv_t *uri = kv_get(set, "host"); + if (sip && when && uri ) { + add_hit(CF.kvz,sip->val,when->val,uri->val); + } + kv_set_free(set); + } + zmq_msg_close(&msg); + CF.frames_processed++; + } + + if (items[1].revents & ZMQ_POLLIN) { // control socket + cp_exec(CF.zcontrol, CF.zcontrol_socket); + CF.controls++; + } + } +} + +int main(int argc, char *argv[]) { + int opt,keepgoing=1; + pthread_t th; + void *res; + + while ( (opt = getopt(argc, argv, "v+xs:Vq:w")) != -1) { + switch (opt) { + case 'v': CF.verbose++; break; + case 'V': show_version(argv[0]); break; + case 's': CF.spool=strdup(optarg); break; + case 'x': CF.exit_when_spool_consumed=1; break; + case 'q': CF.zcontrol_endpoint=strdup(optarg); break; + case 'w': CF.walltime_mode=1; break; + default: usage(argv[0]); break; + } + } + + if (!CF.spool) usage(argv[0]); + if (setup_zmq() == -1) goto program_exit; + + CF.kvz = new_kvz(); + CF.zcontrol = cp_init(cmds,NULL); + s_catch_signals(); + pthread_create(&CF.spr_thread,NULL,spr,NULL); + msg_loop(); + + program_exit: + fprintf(stderr,"frames read: %u\n", CF.frames_read); + fprintf(stderr,"frames processed: %u\n", CF.frames_processed); + fprintf(stderr,"control commands: %u\n", CF.controls); + if (CF.spr_push_socket) zmq_close(CF.spr_push_socket); + if (CF.spr_pull_socket) zmq_close(CF.spr_pull_socket); + if (CF.zcontrol_socket) zmq_close(CF.zcontrol_socket); + if (CF.zmq_context) zmq_term(CF.zmq_context); + if (CF.spool) free(CF.spool); + if (CF.kvz) free_kvz(CF.kvz); + if (CF.s) utstring_free(CF.s); +} + diff --git a/zmq_app/example/kvzuri.h b/zmq_app/example/kvzuri.h new file mode 100644 index 0000000..fa2194b --- /dev/null +++ b/zmq_app/example/kvzuri.h @@ -0,0 +1,53 @@ +#include +#include +#include "uthash.h" +#include "ts.h" +#include "tracker.h" + +#define URI_BUCKETS 64 +#define LN_URI_BUCKETS 6 + +typedef struct { + char ip[16]; // key + ts_t *hits_1h; + ts_t *maps_1h; + ts_t *hits_1w; + ts_t *etop_1w; + time_t last; + UT_hash_handle hh; +} user_t; + +typedef struct { + user_t *users; + // enterprise + ts_t *hits_1h; + ts_t *maps_1h; + ts_t *hits_1w; + tracker_t *uri_tracker; + time_t last; +} kvz_t; + + +struct _CF { + kvz_t *kvz; + int verbose; + int frames_read; + int frames_processed; + int controls; + char *spool; + int exit_when_spool_consumed; // for testing, instead of blocking + void *zmq_context; + void *spr_push_socket; + void *spr_pull_socket; + void *zcontrol_socket; + char *zcontrol_endpoint; // e.g. tcp://eth0:3333 + pthread_t spr_thread; + int request_exit; + int walltime_mode; + void *zcontrol; + UT_string *s; // scratch space +}; + +#define adim(x) (sizeof(x)/sizeof(*x)) +#define ZCON_DEF_ENDPOINT "tcp://127.0.0.1:3333" + diff --git a/zmq_app/example/kvzuri_cmds.c b/zmq_app/example/kvzuri_cmds.c new file mode 100644 index 0000000..a946f25 --- /dev/null +++ b/zmq_app/example/kvzuri_cmds.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "zcontrol.h" +#include "utarray.h" +#include "kvzuri.h" + +extern struct _CF CF; + +/* some control port commands */ +int shutdown_cmd(void *cp, cp_arg_t *arg, void *data) { + cp_add_replys(cp,"shutting down"); + pthread_kill(CF.spr_thread,SIGINT); +} + +int stats_cmd(void *cp, cp_arg_t *arg, void *data) { + utstring_renew(CF.s); + utstring_printf(CF.s, "frames_read: %u\n", CF.frames_read); + utstring_printf(CF.s, "frames_processed: %u\n", CF.frames_processed); + cp_add_reply(cp,utstring_body(CF.s),utstring_len(CF.s)); +} + +void print_int_buckets(ts_t *t, UT_string *s) { + int i; + utstring_printf(s,"[ "); + for(i=0; i < t->num_buckets; i++) { + utstring_printf(s, "%c%u", (i?',':' '),*(unsigned*)(bkt(t,i)->data)); + } + utstring_printf(s,"],\n "); +} + +void print_top(tracker_t *t, UT_string *s) { + uri_t **up=NULL,*u; int i=0; + utstring_printf(s,"{ "); + while( (up=(uri_t**)utarray_next(&t->top,up))) { + u = *up; + utstring_printf(s, "%c%s: [%u,%lu] ", (i++?',':' '), + utstring_body(&u->uri), u->count, (long)u->last); + } + utstring_printf(s," },\n"); +} + +// slot: 60 buckets each 60 sec long (1hour). +// each bucket contains a uri hash histogram +void print_map(ts_t *t, UT_string *s) { + int i,j; + unsigned sum[URI_BUCKETS], bkt_count, total=0; + memset(sum,0,sizeof(int)*URI_BUCKETS); + for(i=0; i < t->num_buckets; i++) { + for(j=0; j < URI_BUCKETS; j++) { + bkt_count = ((unsigned*)(bkt(t,i)->data))[j]; + sum[j] += bkt_count; + total += bkt_count; + } + } + utstring_printf(s, "[ "); + for(j=0; j < URI_BUCKETS; j++) { + utstring_printf(s, "%c%.3f", (j?',':' '), sum[j]*1.0/total); + } + utstring_printf(s, " ],\n"); +} + +int enterprise_cmd(void *cp, cp_arg_t *arg, void *data) { + utstring_renew(CF.s); + utstring_printf(CF.s, "{\n"); + utstring_printf(CF.s, " \"last\": %lu,\n", (long)CF.kvz->last); + utstring_printf(CF.s, " \"hits_1h\": "); print_int_buckets(CF.kvz->hits_1h,CF.s); + utstring_printf(CF.s, " \"hits_1w\": "); print_int_buckets(CF.kvz->hits_1w,CF.s); + utstring_printf(CF.s, " \"maps_1h\": "); print_map(CF.kvz->maps_1h,CF.s); + utstring_printf(CF.s, " \"top\": "); print_top(CF.kvz->uri_tracker,CF.s); + utstring_printf(CF.s, "}\n"); + cp_add_reply(cp,utstring_body(CF.s),utstring_len(CF.s)); +} + +int user_cmd(void *cp, cp_arg_t *arg, void *data) { + user_t *u; + char *user_ip; + + if (arg->argc < 2) { cp_add_replys(cp,"no user specified"); return; } + + // if user is '-' just grab the last one (most recent insert) for testing + user_ip = arg->argv[1]; + if (*user_ip=='-') u=CF.kvz->users; + else HASH_FIND_STR(CF.kvz->users, user_ip, u); + + if (!u) { cp_add_replys(cp,"no such user"); return; } + + utstring_renew(CF.s); + utstring_printf(CF.s, "{\n"); + utstring_printf(CF.s, " \"user\": \"%s\",\n", u->ip); + utstring_printf(CF.s, " \"last\": %lu,\n", (long)u->last); + utstring_printf(CF.s, " \"hits_1h\": "); print_int_buckets(u->hits_1h,CF.s); + utstring_printf(CF.s, " \"hits_1w\": "); print_int_buckets(u->hits_1w,CF.s); + utstring_printf(CF.s, " \"maps_1h\": "); print_map(u->maps_1h,CF.s); + utstring_printf(CF.s, " \"top\": \"TODO\"\n"); + utstring_printf(CF.s, "}\n"); + cp_add_reply(cp,utstring_body(CF.s),utstring_len(CF.s)); +} + +cp_cmd_t cmds[] = { + {"stats", stats_cmd, "server stats"}, + {"user", user_cmd, "get user data"}, + {"enterprise", enterprise_cmd, "enterprise server"}, + {"shutdown", shutdown_cmd, "shutdown server"}, + {NULL, NULL, NULL}, +}; + diff --git a/zmq_app/example/tracker.c b/zmq_app/example/tracker.c new file mode 100644 index 0000000..5735079 --- /dev/null +++ b/zmq_app/example/tracker.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include "tracker.h" + +/* + * keep a backward looking event record of x uri's + * (uniquely) associated with counts of each one + * use a constant time algorithm to maintain a top-Y + * list. the idea here is that x is long enough for + * the true top sites to tick often enough that their + * entry does not fall out of the hash table. + * intended for use with x >>>> y + * + */ + +static void uri_init(uri_t *uri) { utstring_init(&uri->uri); } +static void uri_fini(uri_t *uri) { utstring_done(&uri->uri); } + +tracker_t *tracker_new(int cache_sz, int top_sz) { + int i; + tracker_t *t = calloc(1,sizeof(tracker_t)); + if (!t) return NULL; + t->uri_cache = malloc(cache_sz * sizeof(uri_t)); + if (!t->uri_cache) {free(t); return NULL;} + t->cache_sz = cache_sz; + t->top_sz = top_sz; + t->free_uri = t->uri_cache; + t->free_count = t->cache_sz; + for(i=0; icache_sz; i++) uri_init(&t->uri_cache[i]); + utarray_init(&t->top,&ut_ptr_icd); + return t; +} + +// sort uri's by count. if count is equal sort old-to-new +static int topsort_low_to_high(const void *_a, const void *_b) { + uri_t **a = (uri_t**)_a; + uri_t **b = (uri_t**)_b; + int c = ((*a)->count - (*b)->count); + if (c) return c; + return (*a)->last - (*b)->last; +} + +static int is_top(tracker_t *t, uri_t *u) { + size_t l = utarray_len(&t->top); + if (l < t->top_sz) return 1; + uri_t **f = (uri_t**)utarray_front(&t->top); + if (u->count >= (*f)->count) return 1; + return 0; +} + +static uri_t **lfind_in_top(tracker_t *t, uri_t *u) { + uri_t **up=NULL; + while( (up=(uri_t**)utarray_next(&t->top,up))) { + if (u == *up) return up; + } + return NULL; +} + +void tracker_hit(tracker_t *t, char *uri, time_t when) { + uri_t *u; + HASH_FIND(hh, t->head, uri, strlen(uri), u); + if (!u) { + // delete oldest one if at max + if (HASH_COUNT(t->head) == t->cache_sz) { + uri_t *oldest = t->head; + HASH_DELETE(hh, t->head, oldest); + t->free_uri = oldest; + t->free_count=1; + if (is_top(t,oldest)) { // if it was in top list, clear record + uri_t **p = lfind_in_top(t,oldest); + if (p) utarray_erase(&t->top,utarray_eltidx(&t->top,p),1); + } + } + // claim first free slot + u = t->free_uri; assert(u); + t->free_uri = (--t->free_count) ? (t->free_uri+1) : NULL; + utstring_clear(&u->uri); + utstring_bincpy(&u->uri, uri, strlen(uri)); + u->count=0; + u->last=0; + } else { + HASH_DELETE(hh, t->head, u); // before promoting to newest + } + char *uri_ptr = utstring_body(&u->uri); + int uri_len = utstring_len(&u->uri); + HASH_ADD_KEYPTR(hh, t->head, uri_ptr, uri_len, u); //newest + u->count++; + if (when > u->last) u->last=when; + if (is_top(t,u)) { // maintain top list + // may have higher-count items in t->uri_cache but + // to avoid rescanning we'll insert this one. let + // statistics keep top good as long as cache_sz is + // long enough so true top sites don't roll off + // between their periodic events coming in + if (!lfind_in_top(t,u)) utarray_push_back(&t->top,&u); + utarray_sort(&t->top,topsort_low_to_high); + if (utarray_len(&t->top) > t->top_sz) utarray_erase(&t->top,0,1); + } +} + +void show_tracker(tracker_t *t) { + uri_t *u, *tmp; + HASH_ITER(hh, t->head, u, tmp) { + printf(" %s: %d\n", utstring_body(&u->uri), u->count); + } + printf("\n"); +} + +void show_tracker_top(tracker_t *t) { + uri_t **up=NULL,*u; + while( (up=(uri_t**)utarray_next(&t->top,up))) { + u = *up; + printf(" top> %s: %d\n", utstring_body(&u->uri), u->count); + } + printf("\n"); +} + +void tracker_free(tracker_t *t) { + int i; + HASH_CLEAR(hh,t->head); + for(i=0; icache_sz; i++) uri_fini(&t->uri_cache[i]); + free(t->uri_cache); + utarray_done(&t->top); + free(t); +} diff --git a/zmq_app/example/tracker.h b/zmq_app/example/tracker.h new file mode 100644 index 0000000..5e7ab3c --- /dev/null +++ b/zmq_app/example/tracker.h @@ -0,0 +1,31 @@ +#include +#include "utstring.h" +#include "utarray.h" +#include "uthash.h" + +/* tracker for top X sites in last Y requests */ + +// this takes about 124 bytes per URI +// so to track 1M unique URI's takes about 118 mb +typedef struct { + UT_string uri; + time_t last; + unsigned count; + UT_hash_handle hh; +} uri_t; + +typedef struct { + uri_t *head; + uri_t *uri_cache; + UT_array top; + int cache_sz; // Y + int top_sz; // X + uri_t *free_uri; + int free_count; // contiguous free slots starting at free_uri +} tracker_t; + +tracker_t *tracker_new(int cache_sz, int top_sz); +void tracker_hit(tracker_t *t, char *uri, time_t when); +void tracker_free(tracker_t *t); +void show_tracker(tracker_t *t); +void show_tracker_top(tracker_t *t); diff --git a/zmq_app/example/tracker_tests/Makefile b/zmq_app/example/tracker_tests/Makefile new file mode 100644 index 0000000..225d92f --- /dev/null +++ b/zmq_app/example/tracker_tests/Makefile @@ -0,0 +1,28 @@ +SRCS = $(wildcard test*.c) +PROGS = $(patsubst %.c,%,$(SRCS)) + +LIBDIR = .. +LIB = ../libtracker.a +LDFLAGS = -L$(LIBDIR) -ltracker + +CFLAGS = -I$(LIBDIR) -fno-strict-aliasing -I../../.. +CFLAGS += -g +CFLAGS += -Wall +CFLAGS += ${EXTRA_CFLAGS} + +TEST_TARGET=run_tests +TESTS=./do_tests + +all: $(PROGS) $(TEST_TARGET) + +$(PROGS): $(LIB) + $(CC) $(CFLAGS) -o $@ $(@).c $(LDFLAGS) + +run_tests: $(PROGS) + perl $(TESTS) + +.PHONY: clean + +clean: + rm -f $(PROGS) test*.out + rm -rf *.dSYM diff --git a/zmq_app/example/tracker_tests/do_tests b/zmq_app/example/tracker_tests/do_tests new file mode 100755 index 0000000..574403f --- /dev/null +++ b/zmq_app/example/tracker_tests/do_tests @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/zmq_app/example/tracker_tests/test1.ans b/zmq_app/example/tracker_tests/test1.ans new file mode 100644 index 0000000..e69de29 diff --git a/zmq_app/example/tracker_tests/test1.c b/zmq_app/example/tracker_tests/test1.c new file mode 100644 index 0000000..f1ef0af --- /dev/null +++ b/zmq_app/example/tracker_tests/test1.c @@ -0,0 +1,8 @@ +#include +#include "tracker.h" + +int main() { + tracker_t *t = tracker_new(10,5); + tracker_free(t); + return 0; +} diff --git a/zmq_app/example/tracker_tests/test2.ans b/zmq_app/example/tracker_tests/test2.ans new file mode 100644 index 0000000..eb823f7 --- /dev/null +++ b/zmq_app/example/tracker_tests/test2.ans @@ -0,0 +1,51 @@ + 1: 1 + + 1: 2 + + 1: 2 + 2: 1 + + 1: 2 + 2: 1 + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + + 2: 1 + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + 2: 2 + + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + 2: 2 + 12: 1 + diff --git a/zmq_app/example/tracker_tests/test2.c b/zmq_app/example/tracker_tests/test2.c new file mode 100644 index 0000000..d9bef7e --- /dev/null +++ b/zmq_app/example/tracker_tests/test2.c @@ -0,0 +1,32 @@ +#include +#include +#include "tracker.h" + +time_t when = 1317213882; + +int main() { + tracker_t *t = tracker_new(10,5); + tracker_hit(t,"1",when); show_tracker(t); + tracker_hit(t,"1",when); show_tracker(t); + tracker_hit(t,"2",when); show_tracker(t); + tracker_hit(t,"3",when); + tracker_hit(t,"4",when); + tracker_hit(t,"5",when); + tracker_hit(t,"6",when); + tracker_hit(t,"7",when); + tracker_hit(t,"8",when); + tracker_hit(t,"9",when); + tracker_hit(t,"10",when); show_tracker(t); + + // should induce expiration/slot re-use of 1: + tracker_hit(t,"11",when); show_tracker(t); + + // add a hit to slot 2 to move it to the newest position + tracker_hit(t,"2",when); show_tracker(t); + + // now this should expire slot 3 + tracker_hit(t,"12",when); show_tracker(t); + + tracker_free(t); + return 0; +} diff --git a/zmq_app/example/tracker_tests/test3.ans b/zmq_app/example/tracker_tests/test3.ans new file mode 100644 index 0000000..a79fc8a --- /dev/null +++ b/zmq_app/example/tracker_tests/test3.ans @@ -0,0 +1,68 @@ + 1: 2 + 2: 1 + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + + top> 7: 1 + top> 8: 1 + top> 9: 1 + top> 10: 1 + top> 1: 2 + + 2: 1 + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + + top> 7: 1 + top> 8: 1 + top> 9: 1 + top> 10: 1 + top> 11: 1 + + 3: 1 + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + 2: 2 + + top> 8: 1 + top> 9: 1 + top> 10: 1 + top> 11: 1 + top> 2: 2 + + 4: 1 + 5: 1 + 6: 1 + 7: 1 + 8: 1 + 9: 1 + 10: 1 + 11: 1 + 2: 2 + 12: 1 + + top> 9: 1 + top> 10: 1 + top> 11: 1 + top> 12: 1 + top> 2: 2 + diff --git a/zmq_app/example/tracker_tests/test3.c b/zmq_app/example/tracker_tests/test3.c new file mode 100644 index 0000000..2398bb3 --- /dev/null +++ b/zmq_app/example/tracker_tests/test3.c @@ -0,0 +1,37 @@ +#include +#include +#include "tracker.h" + +time_t when = 1317213882; + +int main() { + tracker_t *t = tracker_new(10,5); + tracker_hit(t,"1",when); + tracker_hit(t,"1",when); + tracker_hit(t,"2",when); + tracker_hit(t,"3",when); + tracker_hit(t,"4",when); + tracker_hit(t,"5",when); + tracker_hit(t,"6",when); + tracker_hit(t,"7",when); + tracker_hit(t,"8",when); + tracker_hit(t,"9",when); + tracker_hit(t,"10",when); + show_tracker(t); + show_tracker_top(t); + + tracker_hit(t,"11",when); + show_tracker(t); + show_tracker_top(t); + + tracker_hit(t,"2",when); + show_tracker(t); + show_tracker_top(t); + + tracker_hit(t,"12",when); + show_tracker(t); + show_tracker_top(t); + + tracker_free(t); + return 0; +} diff --git a/zmq_app/example/tracker_tests/test4.ans b/zmq_app/example/tracker_tests/test4.ans new file mode 100644 index 0000000..e5b2ae4 --- /dev/null +++ b/zmq_app/example/tracker_tests/test4.ans @@ -0,0 +1,51 @@ + 1: 10 + 2: 9 + 3: 8 + 4: 7 + 5: 6 + 6: 5 + 7: 4 + 8: 3 + 9: 2 + 10: 1 + + top> 5: 6 + top> 4: 7 + top> 3: 8 + top> 2: 9 + top> 1: 10 + + 2: 9 + 3: 8 + 4: 7 + 5: 6 + 6: 5 + 7: 4 + 8: 3 + 9: 2 + 10: 1 + 11: 10 + + top> 5: 6 + top> 4: 7 + top> 3: 8 + top> 2: 9 + top> 11: 10 + + 3: 8 + 4: 7 + 5: 6 + 6: 5 + 7: 4 + 8: 3 + 9: 2 + 10: 1 + 11: 10 + 12: 1 + + top> 12: 1 + top> 5: 6 + top> 4: 7 + top> 3: 8 + top> 11: 10 + diff --git a/zmq_app/example/tracker_tests/test4.c b/zmq_app/example/tracker_tests/test4.c new file mode 100644 index 0000000..d667510 --- /dev/null +++ b/zmq_app/example/tracker_tests/test4.c @@ -0,0 +1,34 @@ +#include +#include +#include "tracker.h" + +time_t when = 1317213882; + +int main() { + int i; + tracker_t *t = tracker_new(10,5); + for(i=0;i<10;i++) tracker_hit(t,"1",when); + for(i=0;i<9;i++) tracker_hit(t,"2",when); + for(i=0;i<8;i++) tracker_hit(t,"3",when); + for(i=0;i<7;i++) tracker_hit(t,"4",when); + for(i=0;i<6;i++) tracker_hit(t,"5",when); + for(i=0;i<5;i++) tracker_hit(t,"6",when); + for(i=0;i<4;i++) tracker_hit(t,"7",when); + for(i=0;i<3;i++) tracker_hit(t,"8",when); + for(i=0;i<2;i++) tracker_hit(t,"9",when); + for(i=0;i<1;i++) tracker_hit(t,"10",when); + + show_tracker(t); + show_tracker_top(t); + + for(i=0;i<10;i++) tracker_hit(t,"11",when); + show_tracker(t); + show_tracker_top(t); + + tracker_hit(t,"12",when); + show_tracker(t); + show_tracker_top(t); + + tracker_free(t); + return 0; +} diff --git a/zmq_app/kvz.c b/zmq_app/kvz.c new file mode 100644 index 0000000..38ca549 --- /dev/null +++ b/zmq_app/kvz.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "zcontrol.h" +#include "utarray.h" +#include "kvz.h" + +struct _CF CF = { + .zcontrol_endpoint = ZCON_DEF_ENDPOINT, +}; + +ts_mm hits_1h_mm = {.sz=sizeof(int)}; + +extern cp_cmd_t cmds[]; + +static void s_signal_handler (int signal_value) { + CF.request_exit = 1; +} + +static void s_catch_signals (void) { + struct sigaction action; + action.sa_handler = s_signal_handler; + action.sa_flags = 0; + sigemptyset (&action.sa_mask); + sigaction (SIGINT, &action, NULL); + sigaction (SIGTERM, &action, NULL); +} + +void show_version(char *prog) { + fprintf(stderr, "%s 0.1\n", prog); + int major, minor, patch; + zmq_version (&major, &minor, &patch); + fprintf(stderr,"Current 0MQ version is %d.%d.%d\n", major, minor, patch); + exit(-1); +} + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-s spool] [-x] [-V]\n", prog); + exit(-1); +} + +// this function runs in a separate thread that pushes to main thread +static void* spr(void *data) { + void *sp=NULL; + int rc=-1, block=!CF.exit_when_spool_consumed; + + if ( (sp = kv_spoolreader_new(CF.spool,NULL)) == NULL) { + fprintf(stderr, "failed to open %s\n", CF.spool); + goto abnormal_exit; + } + + zmq_msg_t msg; + void *set; + while(CF.request_exit==0) { + set = kv_set_new(); + if (kv_spool_read(sp, set, block) != 1) break; + if (zmq_msg_init_size(&msg, sizeof(void*))) break; + memcpy(zmq_msg_data(&msg), &set, sizeof(void*)); + if (zmq_send(CF.spr_push_socket, &msg, 0)) break; + if (zmq_msg_close(&msg)) break; + CF.frames_read++; + } + + abnormal_exit: + if (sp) kv_spoolreader_free(sp); + fprintf(stderr, "spool reader exiting\n"); + CF.request_exit=1; + // kick the main loop to fall out of msg-recv and honor exit request */ + zmq_msg_init_size(&msg, 0); + zmq_send(CF.spr_push_socket, &msg, 0); + zmq_msg_close(&msg); + return NULL; +} + +int setup_zmq() { + int zero=0; uint64_t one=1; + if (( (CF.zmq_context = zmq_init(1)) == NULL) || + ( (CF.spr_push_socket = zmq_socket(CF.zmq_context, ZMQ_PUSH)) == NULL) || + ( (CF.spr_pull_socket = zmq_socket(CF.zmq_context, ZMQ_PULL)) == NULL) || + ( (CF.zcontrol_socket = zmq_socket(CF.zmq_context, ZMQ_REP )) == NULL) || + ( zmq_setsockopt(CF.spr_push_socket, ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_setsockopt(CF.spr_pull_socket, ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_setsockopt(CF.spr_push_socket, ZMQ_HWM, &one, sizeof(one))) || + ( zmq_setsockopt(CF.zcontrol_socket , ZMQ_LINGER, &zero, sizeof(zero))) || + ( zmq_bind(CF.zcontrol_socket, CF.zcontrol_endpoint ) != 0) || + ( zmq_bind( CF.spr_push_socket, "inproc://spr") != 0) || + ( zmq_connect(CF.spr_pull_socket, "inproc://spr") != 0)) { + fprintf(stderr,"zeromq setup failed: %s\n", zmq_strerror(errno)); + return -1; + } + return 0; +} + +void msg_loop() { + + zmq_pollitem_t items [] = { + { CF.spr_pull_socket, 0, ZMQ_POLLIN, 0 }, + { CF.zcontrol_socket, 0, ZMQ_POLLIN, 0 }, + }; + + while (CF.request_exit==0) { + zmq_msg_t msg; + zmq_poll (items, adim(items), -1); + + if (items[0].revents & ZMQ_POLLIN) { // spool reader socket + zmq_msg_init (&msg); + if (zmq_recv(CF.spr_pull_socket, &msg, 0)) { + fprintf(stderr,"zmq_recv: %s\n", zmq_strerror(errno)); break; + } + void **_set = zmq_msg_data(&msg); void *set = *_set; + if (zmq_msg_size(&msg) == sizeof(void*)) { + /* set is the kv-set */ + /* fill in application logic here */ + ts_add(CF.frames_1h, time(NULL), NULL); + kv_set_free(set); + } + zmq_msg_close(&msg); + CF.frames_processed++; + } + + if (items[1].revents & ZMQ_POLLIN) { // control socket + cp_exec(CF.zcontrol, CF.zcontrol_socket); + CF.controls++; + } + } +} + +int main(int argc, char *argv[]) { + int opt,keepgoing=1; + pthread_t th; + void *res; + + while ( (opt = getopt(argc, argv, "v+xs:Vq:")) != -1) { + switch (opt) { + case 'v': CF.verbose++; break; + case 'V': show_version(argv[0]); break; + case 's': CF.spool=strdup(optarg); break; + case 'x': CF.exit_when_spool_consumed=1; break; + case 'q': CF.zcontrol_endpoint=strdup(optarg); break; + default: usage(argv[0]); break; + } + } + + if (!CF.spool) usage(argv[0]); + if (setup_zmq() == -1) goto program_exit; + + CF.frames_1h = ts_new(60,60,&hits_1h_mm); + CF.zcontrol = cp_init(cmds,NULL); + s_catch_signals(); + pthread_create(&CF.spr_thread,NULL,spr,NULL); + msg_loop(); + + program_exit: + fprintf(stderr,"frames read: %u\n", CF.frames_read); + fprintf(stderr,"frames processed: %u\n", CF.frames_processed); + fprintf(stderr,"control commands: %u\n", CF.controls); + if (CF.spr_push_socket) zmq_close(CF.spr_push_socket); + if (CF.spr_pull_socket) zmq_close(CF.spr_pull_socket); + if (CF.zcontrol_socket) zmq_close(CF.zcontrol_socket); + if (CF.zmq_context) zmq_term(CF.zmq_context); + if (CF.spool) free(CF.spool); + if (CF.s) utstring_free(CF.s); + if (CF.frames_1h) ts_free(CF.frames_1h); +} + diff --git a/zmq_app/kvz.h b/zmq_app/kvz.h new file mode 100644 index 0000000..196a81d --- /dev/null +++ b/zmq_app/kvz.h @@ -0,0 +1,27 @@ +#include +#include +#include "utstring.h" +#include "ts.h" + +struct _CF { + ts_t *frames_1h; + int verbose; + int frames_read; + int frames_processed; + int controls; + char *spool; + int exit_when_spool_consumed; // for testing, instead of blocking + void *zmq_context; + void *spr_push_socket; + void *spr_pull_socket; + void *zcontrol_socket; + char *zcontrol_endpoint; // e.g. tcp://eth0:3333 + pthread_t spr_thread; + int request_exit; + void *zcontrol; + UT_string *s; /* scratch */ +}; + +#define adim(x) (sizeof(x)/sizeof(*x)) +#define ZCON_DEF_ENDPOINT "tcp://127.0.0.1:3333" + diff --git a/zmq_app/kvz_cmds.c b/zmq_app/kvz_cmds.c new file mode 100644 index 0000000..aa80c4b --- /dev/null +++ b/zmq_app/kvz_cmds.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include "kvspool.h" +#include "zcontrol.h" +#include "utarray.h" +#include "kvz.h" + +extern struct _CF CF; + +/* some control port commands */ +int shutdown_cmd(void *cp, cp_arg_t *arg, void *data) { + cp_add_replys(cp,"shutting down"); + pthread_kill(CF.spr_thread,SIGINT); +} + +int stats_cmd(void *cp, cp_arg_t *arg, void *data) { + utstring_renew(CF.s); + utstring_printf(CF.s, "frames_read: %u\n", CF.frames_read); + utstring_printf(CF.s, "frames_processed: %u\n", CF.frames_processed); + cp_add_reply(cp,utstring_body(CF.s),utstring_len(CF.s)); +} + +int rates_cmd(void *cp, cp_arg_t *arg, void *data) { + utstring_renew(CF.s); + unsigned i,hits; + char *when; + for(i=0; inum_buckets; i++) { + hits = *(unsigned*)(bkt(CF.frames_1h,i)->data); + when = asctime(localtime(&(bkt(CF.frames_1h,i)->start))); + utstring_printf(CF.s, " %u frames: %s", hits, when); + } + cp_add_reply(cp,utstring_body(CF.s),utstring_len(CF.s)); +} + +cp_cmd_t cmds[] = { + {"stats", stats_cmd, "server stats"}, + {"shutdown", shutdown_cmd, "shutdown server"}, + {"rates", rates_cmd, "ingest rates over 1h"}, + {NULL, NULL, NULL}, +}; + diff --git a/zmq_app/ts.c b/zmq_app/ts.c new file mode 100644 index 0000000..3ebdaec --- /dev/null +++ b/zmq_app/ts.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include "ts.h" + +static void ts_def_clear(char *data, size_t sz) { memset(data,0,sz); } +static void ts_def_incr(int *cur, int *incr) { *cur += (incr ? (*incr) : 1); } +static void ts_def_show(int *cur) { printf("%d\n",*cur); } + +ts_t *ts_new(unsigned num_buckets, unsigned secs_per_bucket, const ts_mm *mm) { + int i; + ts_t *t = calloc(1,sizeof(ts_t)); if (!t) return NULL; + t->secs_per_bucket = secs_per_bucket; + t->num_buckets = num_buckets; + t->mm = *mm; /* struct copy */ + // pad sz so sequential buckets' time_t are naturally aligned + int pad = ((t->mm.sz % sizeof(ts_bucket)) > 0) ? + (sizeof(ts_bucket) - (t->mm.sz % sizeof(ts_bucket))) : + 0; + t->mm.sz += pad; + if (t->mm.ctor == NULL) t->mm.ctor = (ts_ctor_f*)ts_def_clear; + if (t->mm.data == NULL) { + if (mm->sz == sizeof(int)) t->mm.data = (ts_data_f*)ts_def_incr; + else assert(0); + } + if (t->mm.show == NULL) { + if (mm->sz == sizeof(int)) t->mm.show = (ts_show_f*)ts_def_show; + } + t->buckets = calloc(num_buckets,sizeof(ts_bucket)+t->mm.sz); + if (t->buckets == NULL) { free(t); return NULL; } + for(i=0; inum_buckets; i++) { + //fprintf(stderr,"t->buckets %p bkt(t,%d) %p\n", t->buckets, i, bkt(t,i)); + bkt(t,i)->start = i * t->secs_per_bucket; + t->mm.ctor(bkt(t,i)->data,t->mm.sz); + } + return t; +} + +void ts_add(ts_t *t, time_t when, void *data) { + int i; + if (bkt(t,0)->start > when) return; // too old + /* figure out bucket it should go in */ + unsigned idx = (when - bkt(t,0)->start) / t->secs_per_bucket; + if (idx >= t->num_buckets) { // shift + unsigned shift = (idx - t->num_buckets) + 1; + if (shift > t->num_buckets) shift = t->num_buckets; + if (shift <= t->num_buckets) { + if (t->mm.dtor) { + for(i=0; imm.dtor(bkt(t,i)->data); + } + } + if (shift < t->num_buckets) { + memmove(bkt(t,0),bkt(t,shift),(t->num_buckets-shift)*(sizeof(ts_bucket)+t->mm.sz)); + } + if (shift) { + for(i=t->num_buckets-shift; inum_buckets; i++) { + t->mm.ctor(bkt(t,i)->data,t->mm.sz); + bkt(t,i)->start = (i > 0) ? (bkt(t,i-1)->start + t->secs_per_bucket) : when; + } + } + idx = (when - bkt(t,0)->start) / t->secs_per_bucket; + assert(idx < t->num_buckets); + } + void *cur = bkt(t,idx)->data; + t->mm.data(cur,data); +} + +void ts_free(ts_t *t) { + int i; + if (t->mm.dtor) { + for(i=0; inum_buckets; i++) t->mm.dtor(bkt(t,i)->data); + } + free(t->buckets); + free(t); +} + +void ts_show(ts_t *t) { + int i; + for(i=0; inum_buckets; i++) { + printf("#%d(%lu): ", i, (long)(bkt(t,i)->start)); + if (t->mm.show) t->mm.show(bkt(t,i)->data); + else printf("\n"); + } + printf("\n"); +} diff --git a/zmq_app/ts.h b/zmq_app/ts.h new file mode 100644 index 0000000..364a83b --- /dev/null +++ b/zmq_app/ts.h @@ -0,0 +1,31 @@ + +typedef void (ts_data_f)(char *cur, char *add); +typedef void (ts_ctor_f)(void *elt, size_t sz); +typedef void (ts_dtor_f)(void *elt); +typedef void (ts_show_f)(void *elt); +typedef struct { + size_t sz; + ts_data_f *data; + ts_ctor_f *ctor; + ts_dtor_f *dtor; + ts_show_f *show; +} ts_mm; + +typedef struct { + time_t start; + char data[]; /* C99 flexible array member */ +} ts_bucket; + +#define bkt(t,i) ((ts_bucket*)((char*)((t)->buckets) + ((i)*(sizeof(ts_bucket)+(t)->mm.sz)))) +typedef struct { + ts_mm mm; + unsigned secs_per_bucket; + unsigned num_buckets; + ts_bucket *buckets; +} ts_t; + +ts_t *ts_new(unsigned num_buckets, unsigned secs_per_bucket, const ts_mm *mm); +void ts_add(ts_t *t, time_t when, void *data); +void ts_free(ts_t *t); +void ts_show(ts_t *t); + diff --git a/zmq_app/ts_tests/Makefile b/zmq_app/ts_tests/Makefile new file mode 100644 index 0000000..5ee6473 --- /dev/null +++ b/zmq_app/ts_tests/Makefile @@ -0,0 +1,27 @@ +SRCS = $(wildcard test*.c) +PROGS = $(patsubst %.c,%,$(SRCS)) + +LIBDIR = .. +LIB = $(LIBDIR)/libts.a + +CFLAGS = -I$(LIBDIR) -fno-strict-aliasing +CFLAGS += -g +CFLAGS += -Wall +CFLAGS += ${EXTRA_CFLAGS} + +TEST_TARGET=run_tests +TESTS=./do_tests + +all: $(PROGS) $(TEST_TARGET) + +$(PROGS): $(LIB) + $(CC) $(CFLAGS) -o $@ $(@).c $(LIB) + +run_tests: $(PROGS) + perl $(TESTS) + +.PHONY: clean + +clean: + rm -f $(PROGS) test*.out + rm -rf *.dSYM diff --git a/zmq_app/ts_tests/do_tests b/zmq_app/ts_tests/do_tests new file mode 100755 index 0000000..574403f --- /dev/null +++ b/zmq_app/ts_tests/do_tests @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/zmq_app/ts_tests/test1.ans b/zmq_app/ts_tests/test1.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/zmq_app/ts_tests/test1.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/zmq_app/ts_tests/test1.c b/zmq_app/ts_tests/test1.c new file mode 100644 index 0000000..1645da1 --- /dev/null +++ b/zmq_app/ts_tests/test1.c @@ -0,0 +1,22 @@ +#include +#include +#include "ts.h" + +void insert(long *cur, long *incr) { *cur += *incr; } +void show(long *i) { printf("%lu\n", *i); } + +const ts_mm mm = {.sz=sizeof(long), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + long one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test2.ans b/zmq_app/ts_tests/test2.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/zmq_app/ts_tests/test2.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/zmq_app/ts_tests/test2.c b/zmq_app/ts_tests/test2.c new file mode 100644 index 0000000..0880584 --- /dev/null +++ b/zmq_app/ts_tests/test2.c @@ -0,0 +1,22 @@ +#include +#include +#include "ts.h" + +void insert(char *cur, char *incr) { *cur += *incr; } +void show(char *i) { printf("%u\n", (unsigned)*i); } + +const ts_mm mm = {.sz=sizeof(char), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + char one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test3.ans b/zmq_app/ts_tests/test3.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/zmq_app/ts_tests/test3.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/zmq_app/ts_tests/test3.c b/zmq_app/ts_tests/test3.c new file mode 100644 index 0000000..71811f4 --- /dev/null +++ b/zmq_app/ts_tests/test3.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "ts.h" + +void insert(uint16_t *cur, uint16_t *incr) { *cur += *incr; } +void show(uint16_t *i) { printf("%u\n", (unsigned)*i); } + +const ts_mm mm = {.sz=sizeof(uint16_t), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + uint16_t one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test4.ans b/zmq_app/ts_tests/test4.ans new file mode 100644 index 0000000..d331ca4 --- /dev/null +++ b/zmq_app/ts_tests/test4.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 4 +#1(565): 0 +#2(575): 1 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/zmq_app/ts_tests/test4.c b/zmq_app/ts_tests/test4.c new file mode 100644 index 0000000..bc5c8d8 --- /dev/null +++ b/zmq_app/ts_tests/test4.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "ts.h" + +typedef struct { + char c[7]; +} seven_t; + +void insert(seven_t *cur, seven_t *incr) { cur->c[0]++; } +void show(seven_t *i) { printf("%u\n", (unsigned)(i->c[0])); } + +const ts_mm mm = {.sz=sizeof(seven_t), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, NULL); ts_show(t); + ts_add(t,100,NULL); ts_show(t); + ts_add(t,120,NULL); ts_show(t); + ts_add(t,555,NULL); //ts_show(t); + ts_add(t,555,NULL); //ts_show(t); + ts_add(t,556,NULL); //ts_show(t); + ts_add(t,564,NULL); //ts_show(t); + ts_add(t,575,NULL); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test5.ans b/zmq_app/ts_tests/test5.ans new file mode 100644 index 0000000..8465610 --- /dev/null +++ b/zmq_app/ts_tests/test5.ans @@ -0,0 +1,55 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(30): 1 +#1(40): 1 +#2(50): 1 +#3(60): 1 +#4(70): 1 +#5(80): 1 +#6(90): 1 +#7(100): 1 +#8(110): 0 +#9(120): 1 + +#0(555): 1 +#1(565): 0 +#2(575): 0 +#3(585): 0 +#4(595): 0 +#5(605): 0 +#6(615): 0 +#7(625): 0 +#8(635): 0 +#9(645): 0 + diff --git a/zmq_app/ts_tests/test5.c b/zmq_app/ts_tests/test5.c new file mode 100644 index 0000000..d17fe8e --- /dev/null +++ b/zmq_app/ts_tests/test5.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "ts.h" + +void insert(uint64_t *cur, uint64_t *incr) { *cur += *incr; } +void show(uint64_t *i) { printf("%lu\n", (long)*i); } + +const ts_mm mm = {.sz=sizeof(uint64_t), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + uint64_t one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,120,&one); ts_show(t); + ts_add(t,555,&one); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test6.ans b/zmq_app/ts_tests/test6.ans new file mode 100644 index 0000000..e21981c --- /dev/null +++ b/zmq_app/ts_tests/test6.ans @@ -0,0 +1,33 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(0): 3 +#1(10): 3 +#2(20): 3 +#3(30): 3 +#4(40): 3 +#5(50): 3 +#6(60): 3 +#7(70): 3 +#8(80): 3 +#9(90): 3 + diff --git a/zmq_app/ts_tests/test6.c b/zmq_app/ts_tests/test6.c new file mode 100644 index 0000000..1a5f008 --- /dev/null +++ b/zmq_app/ts_tests/test6.c @@ -0,0 +1,19 @@ +#include +#include +#include "ts.h" + +void show(int *i) { printf("%u\n", *i); } + +const ts_mm mm = {.sz=sizeof(int), + .data=NULL, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + int two=2; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, NULL); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &two); ts_show(t); + ts_free(t); + return 0; +} diff --git a/zmq_app/ts_tests/test7.ans b/zmq_app/ts_tests/test7.ans new file mode 100644 index 0000000..8a00ff1 --- /dev/null +++ b/zmq_app/ts_tests/test7.ans @@ -0,0 +1,44 @@ +#0(0): 0 +#1(10): 0 +#2(20): 0 +#3(30): 0 +#4(40): 0 +#5(50): 0 +#6(60): 0 +#7(70): 0 +#8(80): 0 +#9(90): 0 + +#0(0): 1 +#1(10): 1 +#2(20): 1 +#3(30): 1 +#4(40): 1 +#5(50): 1 +#6(60): 1 +#7(70): 1 +#8(80): 1 +#9(90): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + +#0(10): 1 +#1(20): 1 +#2(30): 1 +#3(40): 1 +#4(50): 1 +#5(60): 1 +#6(70): 1 +#7(80): 1 +#8(90): 1 +#9(100): 1 + diff --git a/zmq_app/ts_tests/test7.c b/zmq_app/ts_tests/test7.c new file mode 100644 index 0000000..ae7cd2d --- /dev/null +++ b/zmq_app/ts_tests/test7.c @@ -0,0 +1,21 @@ +#include +#include +#include "ts.h" + +void insert(long *cur, long *incr) { *cur += *incr; } +void show(long *i) { printf("%lu\n", *i); } + +const ts_mm mm = {.sz=sizeof(long), + .data=(ts_data_f*)insert, + .show=(ts_show_f*)show }; +int main() { + time_t i=0; + long one=1; + + ts_t *t = ts_new(10,10,&mm); ts_show(t); + for(i=0; i < 100; i += 10) ts_add(t, i, &one); ts_show(t); + ts_add(t,100,&one); ts_show(t); + ts_add(t,1,&one); ts_show(t); // too old for this ts, should drop + ts_free(t); + return 0; +} diff --git a/zmq_app/zcon.c b/zmq_app/zcon.c new file mode 100644 index 0000000..4eca587 --- /dev/null +++ b/zmq_app/zcon.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct _CF { + int run; + int verbose; + char *zpath; + char *prompt; + void *zmq_context; + void *req_socket; +} CF = { + .run = 1, + .zpath = "tcp://127.0.0.1:3333", + .prompt = "zcon> ", +}; + +void usage(char *prog) { + fprintf(stderr, "usage: %s [-v] [-s server]\n", prog); + fprintf(stderr, " -v verbose\n"); + fprintf(stderr, " -s zmq address of server\n"); + exit(-1); +} + +/* This little parsing function finds one word at a time from the + * input line. It supports double quotes to group words together. */ +const int ws[256] = {[' ']=1, ['\t']=1}; +char *find_word(char *c, char **start, char **end) { + int in_qot=0; + while ((*c != '\0') && ws[*c]) c++; // skip leading whitespace + if (*c == '"') { in_qot=1; c++; } + *start=c; + if (in_qot) { + while ((*c != '\0') && (*c != '"')) c++; + *end = c; + if (*c == '"') { + in_qot=0; c++; + if ((*c != '\0') && !ws[*c]) { + fprintf(stderr,"text follows quoted text without space\n"); return NULL; + } + } + else {fprintf(stderr,"quote mismatch\n"); return NULL;} + } + else { + while ((*c != '\0') && (*c != ' ')) { + if (*c == '"') {fprintf(stderr,"start-quote within word\n"); return NULL; } + c++; + } + *end = c; + } + return c; +} + +#define alloc_msg(n,m) ((m)=realloc((m),(++(n))*sizeof(*(m)))) +int do_rqst(char *line) { + char *c=line, *start=NULL, *end=NULL, *buf; + int nmsgs=0; zmq_msg_t *msgs = NULL; + int rmsgs=0; zmq_msg_t *msgr = NULL; + size_t sz, more_sz=sizeof(int64_t); + int64_t more=0; + int i, rc = -1; + + /* parse the line into argv style words, pack and transmit the request */ + while(*c != '\0') { + if ( (c = find_word(c,&start,&end)) == NULL) goto done; // TODO confirm: normal exit? + //fprintf(stderr,"[%.*s]\n", (int)(end-start), start); + assert(start && end); + alloc_msg(nmsgs,msgs); + buf = start; sz = end-start; + zmq_msg_init_size(&msgs[nmsgs-1],sz); + memcpy(zmq_msg_data(&msgs[nmsgs-1]),buf,sz); + start = end = NULL; + } + + // send request + for(i=0; i +#include +#include +#include +#include "zcontrol.h" +#include "utstring.h" +#include "uthash.h" + +typedef struct { // wraps a command structure + cp_cmd_t cmd; + UT_hash_handle hh; + void *data; +} cp_cmd_w; + +typedef struct { + cp_cmd_w *cmds; // hash table of commands + void *data; // opaque data pointer passed into commands + // fields used during command execution. only one command is + // executing at a time because cp_exec is intended for use + // from only one thread (particularly the 'main' thread) + cp_arg_t arg; + zmq_msg_t *msgs; + int nmsgs; +} cp_t; + +static int help_cmd(void *_cp, cp_arg_t *arg, void *data) { + cp_t *cp = (cp_t*)_cp; + UT_string *t; + utstring_new(t); + cp_cmd_w *cw, *tmp; + HASH_ITER(hh, cp->cmds, cw, tmp) { + utstring_printf(t, "%-20s ", cw->cmd.name); + utstring_printf(t, "%s\n", cw->cmd.help); + } + utstring_printf(t, "%-20s %s\n", "quit", "close session"); + cp_add_reply(cp,utstring_body(t),utstring_len(t)); + utstring_free(t); + return 0; +} + +static int unknown_cmd(void *cp, cp_arg_t *arg, void *data) { + char unknown_msg[] = "command not found\n"; + if (arg->argc == 0) return 0; /* no command; no-op */ + cp_add_reply(cp, unknown_msg, sizeof(unknown_msg)-1); + return -1; +} +// unknown is not registered in the commands hash table +// so we point to this record if we need to invoke it. +static cp_cmd_w unknown_cmdw = {{"unknown",unknown_cmd}}; + +void *cp_init(cp_cmd_t *cmds, void *data) { + cp_cmd_t *cmd; + cp_t *cp; + + if ( (cp=calloc(1,sizeof(cp_t))) == NULL) goto done; + cp->data = data; + cp_add_cmd(cp, "help", help_cmd, "this text", NULL); + for(cmd=cmds; cmd && cmd->name; cmd++) { + cp_add_cmd(cp,cmd->name,cmd->cmdf,cmd->help,data); + } + + done: + return cp; +} + +void cp_add_cmd(void *_cp, char *name, cp_cmd_f *cmdf, char *help, void *data) { + cp_t *cp = (cp_t*)_cp; + cp_cmd_w *cw; + + /* create new command if it isn't in the hash; else update in place */ + HASH_FIND(hh, cp->cmds, name, strlen(name), cw); + if (cw == NULL) { + if ( (cw = malloc(sizeof(*cw))) == NULL) exit(-1); + memset(cw,0,sizeof(*cw)); + cw->cmd.name = strdup(name); + cw->cmd.help = help ? strdup(help) : strdup(""); + HASH_ADD_KEYPTR(hh, cp->cmds, cw->cmd.name, strlen(cw->cmd.name), cw); + } + cw->cmd.cmdf = cmdf; + cw->data = data; +} + +#define alloc_msg(n,m) ((m)=realloc((m),(++(n))*sizeof(*(m)))) +int cp_exec(void *_cp, void *rep) { + cp_t *cp = (cp_t*)_cp; + int rc=-1, i; + cp_cmd_w *cw; + void *tmp; + zmq_msg_t *msgs=NULL; int nmsgs=0; + int64_t more; size_t more_sz=sizeof(int64_t); + + assert(cp->arg.argc == 0); + assert(cp->nmsgs==0); + + /* unpack the msg into argc/argv/lenv for the command callback */ + do { + alloc_msg(nmsgs,msgs); + zmq_msg_init(&msgs[nmsgs-1]); + if (zmq_recv(rep,&msgs[nmsgs-1],0)) { + fprintf(stderr,"zmq_recv: %s\n", zmq_strerror(errno)); + goto done; + } + if (zmq_getsockopt(rep, ZMQ_RCVMORE, &more, &more_sz)) more=0; + } while(more); + + if (nmsgs == 0) {cw = &unknown_cmdw; goto run;} + cp->arg.argc = nmsgs; + cp->arg.argv = calloc(nmsgs,sizeof(char*)); + cp->arg.lenv = calloc(nmsgs,sizeof(size_t)); + if (!cp->arg.argv || !cp->arg.lenv) goto done; + + for(i=0; i < nmsgs; i++) { + char *buf = zmq_msg_data(&msgs[i]); + size_t sz = zmq_msg_size(&msgs[i]); + if ( (cp->arg.argv[i] = malloc(sz+1)) == NULL) goto done; + memcpy(cp->arg.argv[i], buf, sz); + cp->arg.argv[i][sz]='\0'; + cp->arg.lenv[i] = sz; + } + + /* find the command callback */ + HASH_FIND(hh, cp->cmds, cp->arg.argv[0], cp->arg.lenv[0], cw); + if (!cw) cw = &unknown_cmdw; + + /* prepare the output area, run the callback */ + run: + cw->cmd.cmdf(cp, &cp->arg, cw->data); + + /* send reply */ + if (cp->nmsgs == 0) { // special case: command generated no reply, send empty + zmq_msg_t msg; + zmq_msg_init_size(&msg,0); + zmq_send(rep, &msg, 0); + zmq_msg_close(&msg); + } + for(i=0; i < cp->nmsgs; i++) { // normal case, send non-empty command reply + if (zmq_send(rep, &cp->msgs[i], (i<(cp->nmsgs-1))?ZMQ_SNDMORE:0)) { + fprintf(stderr,"zmq_send: %s\n", zmq_strerror(errno)); + goto done; + } + } + + rc = 0; // success + + done: + while (nmsgs) zmq_msg_close(&msgs[--nmsgs]); + while (cp->nmsgs) zmq_msg_close(&cp->msgs[--cp->nmsgs]); cp->msgs=NULL; + while(cp->arg.argc) free(cp->arg.argv[--cp->arg.argc]); + if (cp->arg.argv) { free(cp->arg.argv); cp->arg.argv=NULL; } + if (cp->arg.lenv) { free(cp->arg.lenv); cp->arg.lenv=NULL; } + return rc; +} + +void cp_free(void *_cp) { + cp_t *cp = (cp_t*)_cp; + cp_cmd_w *cw, *tmp; + HASH_ITER(hh, cp->cmds, cw, tmp) { + HASH_DEL(cp->cmds, cw); + free(cw->cmd.name); + free(cw->cmd.help); + free(cw); + } + free(cp); +} + +void cp_add_reply(void *_cp, void *buf, size_t len) { + cp_t *cp = (cp_t*)_cp; + alloc_msg(cp->nmsgs,cp->msgs); + zmq_msg_t *msg = &cp->msgs[cp->nmsgs-1]; + zmq_msg_init_size(msg, len); + memcpy(zmq_msg_data(msg),buf,len); +} + diff --git a/zmq_app/zcontrol.h b/zmq_app/zcontrol.h new file mode 100644 index 0000000..f0d5ec4 --- /dev/null +++ b/zmq_app/zcontrol.h @@ -0,0 +1,30 @@ +#ifndef CONTROL_PORT_H +#define CONTROL_PORT_H + +#include +#include + +typedef struct { + int argc; /* conventional argc/argv args */ + char **argv; + size_t *lenv; // len of each arg, useful if client sends null-containing args +} cp_arg_t; + +typedef int (cp_cmd_f)(void *cp, cp_arg_t *arg, void *data); + +typedef struct { + char *name; + cp_cmd_f *cmdf; + char *help; +} cp_cmd_t; + +void *cp_init(cp_cmd_t *cmds, void *data); +void cp_free(void *_cp); +void cp_add_cmd(void*, char *name, cp_cmd_f *cmdf, char *help, void *data); +int cp_exec(void *_cp, void *zmq_reply_socket); + +/* these are used within command callbacks */ +#define cp_add_replys(a,b) cp_add_reply((a),(b),strlen(b)) +void cp_add_reply(void *, void *buf, size_t len); + +#endif