commit b990aa019e5ad76d67dad578aaf4ae39797047e3 Author: Alexander Vdolainen Date: Mon Nov 24 12:25:18 2014 +0200 initial import 1.2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3df996e --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +*~ +*.o +*.a +*.lo +*.la +*.dvi +*.synctex.gz +.deps +.libs +autom4te.cache/ +Makefile +Makefile.in +aclocal.m4 +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +intltool-extract.in +intltool-merge.in +intltool-update.in +lib/libtdata-0.2.pc +libtool +ltmain.sh +missing +mkinstalldirs +po/Makefile.in.in +po/POTFILES +po/stamp-it +stamp-h1 +include/version.h +.emacs.desktop +nbproject +config.guess.dh-orig +config.sub.dh-orig diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..8ac1c7e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +This software was developed by Askele companies group. + * EU part: http://askele.com + * NW European part of Russia: http://askele-ingria.com +Team: + * General SW Architect and PM: Alexander Vdolainen diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..befd914 --- /dev/null +++ b/COPYING @@ -0,0 +1,3 @@ +Askele business software license. + +Libs and others might be under LGPLv3. \ No newline at end of file diff --git a/COPYING.LGPL3 b/COPYING.LGPL3 new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/COPYING.LGPL3 @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..93ca727 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,10 @@ +2013-09-22 Alexander Vdolainen + * (a set of files): added autotools + +2014-11-23 Alexander Vdolainen + * Initial import of 0.2 version + + +Copyright 2013-2014 Askele, Inc. +Copying and distribution of this file, with or without modification, are +permitted provided the copyright notice and this notice are preserved. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..a1e89e1 --- /dev/null +++ b/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..2f75a16 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = po include lib + +libsexprdocdir = ${prefix}/doc/libsexpr +libsexprdoc_DATA = \ + README\ + COPYING\ + AUTHORS\ + ChangeLog\ + INSTALL\ + NEWS + + +INTLTOOL_FILES = intltool-extract.in \ + intltool-merge.in \ + intltool-update.in + +EXTRA_DIST = $(libsexprdoc_DATA) \ + $(INTLTOOL_FILES) + +DISTCLEANFILES = intltool-extract \ + intltool-merge \ + intltool-update \ + po/.intltool-merge-cache + +clean-local: + + +# Remove doc directory on uninstall +uninstall-local: + -rm -r $(libsexprdocdir) diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..195c730 --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +22.09.2013: Autotools choosen to be a build be. diff --git a/README b/README new file mode 100644 index 0000000..e69e2f7 --- /dev/null +++ b/README @@ -0,0 +1 @@ +1. Build the Debian package: debuild -i -us -uc -b diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..a0ec5ee --- /dev/null +++ b/autogen.sh @@ -0,0 +1,157 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +DIE=0 + +if [ -n "$GNOME2_DIR" ]; then + ACLOCAL_FLAGS="-I $GNOME2_DIR/share/aclocal $ACLOCAL_FLAGS" + LD_LIBRARY_PATH="$GNOME2_DIR/lib:$LD_LIBRARY_PATH" + PATH="$GNOME2_DIR/bin:$PATH" + export PATH + export LD_LIBRARY_PATH +fi + +(test -f $srcdir/configure.ac) || { + echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" + echo " top-level package directory" + exit 1 +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`autoconf' installed." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^IT_PROG_INTLTOOL" $srcdir/configure.ac >/dev/null) && { + (intltoolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`intltool' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.ac >/dev/null) && { + (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`xml-i18n-toolize' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^LT_INIT" $srcdir/configure.ac >/dev/null) && { + (libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`libtool' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + } +} + +(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.ac >/dev/null) && { + (grep "sed.*POTFILES" $srcdir/configure.ac) > /dev/null || \ + (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`glib' installed." + echo "You can get it from: ftp://ftp.gtk.org/pub/gtk" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`automake' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "**Warning**: I am going to run \`configure' with no arguments." + echo "If you wish to pass any to it, please specify them on the" + echo \`$0\'" command line." + echo +fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + +for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.ac -print` +do + dr=`dirname $coin` + if test -f $dr/NO-AUTO-GEN; then + echo skipping $dr -- flagged as no auto-gen + else + echo processing $dr + ( cd $dr + + aclocalinclude="$ACLOCAL_FLAGS" + + if grep "^AM_GLIB_GNU_GETTEXT" configure.ac >/dev/null; then + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running glib-gettextize... Ignore non-fatal messages." + echo "no" | glib-gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + if grep "^IT_PROG_INTLTOOL" configure.ac >/dev/null; then + echo "Running intltoolize..." + intltoolize --copy --force --automake + fi + if grep "^AM_PROG_XML_I18N_TOOLS" configure.ac >/dev/null; then + echo "Running xml-i18n-toolize..." + xml-i18n-toolize --copy --force --automake + fi + if grep "^LT_INIT" configure.ac >/dev/null; then + if test -z "$NO_LIBTOOLIZE" ; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^A[CM]_CONFIG_HEADER" configure.ac >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu $am_opt ..." + automake --add-missing --copy --gnu $am_opt + echo "Running autoconf ..." + autoconf + ) + fi +done + +if test x$NOCONFIGURE = x; then + echo Running $srcdir/configure "$@" ... + $srcdir/configure "$@" \ + && echo Now type \`make\' to compile. || exit 1 +else + echo Skipping configure process. +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d0a1c63 --- /dev/null +++ b/configure.ac @@ -0,0 +1,42 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(libsexpr, 1.2) + +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.11]) + +AM_SILENT_RULES([yes]) + +AC_PROG_CC + +dnl *************************************************************************** +dnl Internationalization +dnl *************************************************************************** +IT_PROG_INTLTOOL([0.35.0]) + +GETTEXT_PACKAGE=libsexpr +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [GETTEXT package name]) +AM_GLIB_GNU_GETTEXT + + +LT_INIT + +dnl ***************** +dnl ***** options ***** +dnl ***************** + +AC_ARG_ENABLE([build_examples], + AS_HELP_STRING([--enable-build-examples], [Enable examples build])) + +AS_IF([test "x$enable_build_examples" = "xyes"], [ + AC_DEFINE([BUILD_EXAMPLES], 1, [build of examples enabled]) +]) + +AC_OUTPUT([ +Makefile +lib/libsexpr-1.2.pc +lib/Makefile +include/Makefile +po/Makefile.in]) diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..04deb78 --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,6 @@ +libsexpr for Debian +------------------- + + + + -- Alexander Vdolainen Mon, 24 Nov 2014 11:52:48 +0200 diff --git a/debian/README.source b/debian/README.source new file mode 100644 index 0000000..90c494e --- /dev/null +++ b/debian/README.source @@ -0,0 +1,9 @@ +libsexpr for Debian +------------------- + + + + + + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..005b2f5 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +libsexpr (1.2-1) unstable; urgency=low + + * Initial release (Closes: #nnnn) + + -- Alexander Vdolainen Mon, 24 Nov 2014 11:52:48 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +8 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..eb42e36 --- /dev/null +++ b/debian/control @@ -0,0 +1,23 @@ +Source: libsexpr +Priority: extra +Maintainer: Alexander Vdolainen +Build-Depends: debhelper (>= 8.0.0), autotools-dev +Standards-Version: 3.9.3 +Section: libs +Homepage: http://askele.com/software +#Vcs-Git: git://git.debian.org/collab-maint/libsexpr.git +#Vcs-Browser: http://git.debian.org/?p=collab-maint/libsexpr.git;a=summary + +Package: libsexpr-dev +Section: libdevel +Architecture: any +Depends: libsexpr (= ${binary:Version}) +Description: Development files for libsexpr + Development files for library working with S-expressions + +Package: libsexpr +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: C library for working with S-expressions + Library used to parse, evaluate S-expressions diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..6ccc712 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,38 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: libsexpr +Source: + +Files: * +Copyright: + +License: + + + . + + +# If you want to use GPL v2 or later for the /debian/* files use +# the following clauses, or change it to suit. Delete these two lines +Files: debian/* +Copyright: 2014 Alexander Vdolainen +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package 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 + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +# Please also look if there are files or directories which have a +# different copyright/license attached and list them here. +# Please avoid to pick license terms that are more restrictive than the +# packaged work, as it may make Debian's contributions unacceptable upstream. diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..50bd824 --- /dev/null +++ b/debian/docs @@ -0,0 +1,2 @@ +NEWS +README diff --git a/debian/emacsen-install.ex b/debian/emacsen-install.ex new file mode 100644 index 0000000..7225107 --- /dev/null +++ b/debian/emacsen-install.ex @@ -0,0 +1,47 @@ +#! /bin/sh -e +# /usr/lib/emacsen-common/packages/install/libsexpr + +# Written by Jim Van Zandt , borrowing heavily +# from the install scripts for gettext by Santiago Vila +# and octave by Dirk Eddelbuettel . + +FLAVOR=$1 +PACKAGE=libsexpr + +if [ ${FLAVOR} = emacs ]; then exit 0; fi + +echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR} + +#FLAVORTEST=`echo $FLAVOR | cut -c-6` +#if [ ${FLAVORTEST} = xemacs ] ; then +# SITEFLAG="-no-site-file" +#else +# SITEFLAG="--no-site-file" +#fi +FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile" + +ELDIR=/usr/share/emacs/site-lisp/${PACKAGE} +ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE} +ELRELDIR=../../../emacs/site-lisp/${PACKAGE} + +# Install-info-altdir does not actually exist. +# Maybe somebody will write it. +if test -x /usr/sbin/install-info-altdir; then + echo install/${PACKAGE}: install Info links for ${FLAVOR} + install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/share/info/${PACKAGE}.info.gz +fi + +install -m 755 -d ${ELCDIR} +cd ${ELDIR} +FILES=`echo *.el` +cd ${ELCDIR} +ln -sf ${ELRELDIR}/*.el . + +cat << EOF > path.el +(debian-pkg-add-load-path-item ".") +(setq byte-compile-warnings nil) +EOF +${FLAVOR} ${FLAGS} ${FILES} +rm -f path.el + +exit 0 diff --git a/debian/emacsen-remove.ex b/debian/emacsen-remove.ex new file mode 100644 index 0000000..4d3c192 --- /dev/null +++ b/debian/emacsen-remove.ex @@ -0,0 +1,15 @@ +#!/bin/sh -e +# /usr/lib/emacsen-common/packages/remove/libsexpr + +FLAVOR=$1 +PACKAGE=libsexpr + +if [ ${FLAVOR} != emacs ]; then + if test -x /usr/sbin/install-info-altdir; then + echo remove/${PACKAGE}: removing Info links for ${FLAVOR} + install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/share/info/libsexpr.info.gz + fi + + echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR} + rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE} +fi diff --git a/debian/emacsen-startup.ex b/debian/emacsen-startup.ex new file mode 100644 index 0000000..b7eb09a --- /dev/null +++ b/debian/emacsen-startup.ex @@ -0,0 +1,27 @@ +;; -*-emacs-lisp-*- +;; +;; Emacs startup file, e.g. /etc/emacs/site-start.d/50libsexpr.el +;; for the Debian libsexpr package +;; +;; Originally contributed by Nils Naumann +;; Modified by Dirk Eddelbuettel +;; Adapted for dh-make by Jim Van Zandt + +;; The libsexpr package follows the Debian/GNU Linux 'emacsen' policy and +;; byte-compiles its elisp files for each 'emacs flavor' (emacs19, +;; xemacs19, emacs20, xemacs20...). The compiled code is then +;; installed in a subdirectory of the respective site-lisp directory. +;; We have to add this to the load-path: +(let ((package-dir (concat "/usr/share/" + (symbol-name debian-emacs-flavor) + "/site-lisp/libsexpr"))) +;; If package-dir does not exist, the libsexpr package must have +;; removed but not purged, and we should skip the setup. + (when (file-directory-p package-dir) + (if (fboundp 'debian-pkg-add-load-path-item) + (debian-pkg-add-load-path-item package-dir) + (setq load-path (cons package-dir load-path))) + (autoload 'libsexpr-mode "libsexpr-mode" + "Major mode for editing libsexpr files." t) + (add-to-list 'auto-mode-alist '("\\.libsexpr$" . libsexpr-mode)))) + diff --git a/debian/init.d.ex b/debian/init.d.ex new file mode 100644 index 0000000..a5f99b8 --- /dev/null +++ b/debian/init.d.ex @@ -0,0 +1,154 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: libsexpr +# Required-Start: $network $local_fs +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: +# Description: +# <...> +# <...> +### END INIT INFO + +# Author: Alexander Vdolainen + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC=libsexpr # Introduce a short description here +NAME=libsexpr # Introduce the short server's name here +DAEMON=/usr/sbin/libsexpr # Introduce the server's location here +DAEMON_ARGS="" # Arguments to run the daemon with +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x $DAEMON ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/debian/libsexpr-dev.dirs b/debian/libsexpr-dev.dirs new file mode 100644 index 0000000..4418816 --- /dev/null +++ b/debian/libsexpr-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include diff --git a/debian/libsexpr-dev.install b/debian/libsexpr-dev.install new file mode 100644 index 0000000..6cd8ddd --- /dev/null +++ b/debian/libsexpr-dev.install @@ -0,0 +1,4 @@ +usr/include/* +usr/lib/lib*.a +usr/lib/lib*.so +usr/lib/pkgconfig/* diff --git a/debian/libsexpr.cron.d.ex b/debian/libsexpr.cron.d.ex new file mode 100644 index 0000000..43a6e44 --- /dev/null +++ b/debian/libsexpr.cron.d.ex @@ -0,0 +1,4 @@ +# +# Regular cron jobs for the libsexpr package +# +0 4 * * * root [ -x /usr/bin/libsexpr_maintenance ] && /usr/bin/libsexpr_maintenance diff --git a/debian/libsexpr.default.ex b/debian/libsexpr.default.ex new file mode 100644 index 0000000..0e0f8c5 --- /dev/null +++ b/debian/libsexpr.default.ex @@ -0,0 +1,10 @@ +# Defaults for libsexpr initscript +# sourced by /etc/init.d/libsexpr +# installed at /etc/default/libsexpr by the maintainer scripts + +# +# This is a POSIX shell fragment +# + +# Additional options that are passed to the Daemon. +DAEMON_OPTS="" diff --git a/debian/libsexpr.dirs b/debian/libsexpr.dirs new file mode 100644 index 0000000..6845771 --- /dev/null +++ b/debian/libsexpr.dirs @@ -0,0 +1 @@ +usr/lib diff --git a/debian/libsexpr.doc-base.EX b/debian/libsexpr.doc-base.EX new file mode 100644 index 0000000..7ef4625 --- /dev/null +++ b/debian/libsexpr.doc-base.EX @@ -0,0 +1,20 @@ +Document: libsexpr +Title: Debian libsexpr Manual +Author: +Abstract: This manual describes what libsexpr is + and how it can be used to + manage online manuals on Debian systems. +Section: unknown + +Format: debiandoc-sgml +Files: /usr/share/doc/libsexpr/libsexpr.sgml.gz + +Format: postscript +Files: /usr/share/doc/libsexpr/libsexpr.ps.gz + +Format: text +Files: /usr/share/doc/libsexpr/libsexpr.text.gz + +Format: HTML +Index: /usr/share/doc/libsexpr/html/index.html +Files: /usr/share/doc/libsexpr/html/*.html diff --git a/debian/libsexpr.install b/debian/libsexpr.install new file mode 100644 index 0000000..d0dbfd1 --- /dev/null +++ b/debian/libsexpr.install @@ -0,0 +1 @@ +usr/lib/lib*.so.* diff --git a/debian/manpage.1.ex b/debian/manpage.1.ex new file mode 100644 index 0000000..87454ad --- /dev/null +++ b/debian/manpage.1.ex @@ -0,0 +1,56 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" (C) Copyright 2014 Alexander Vdolainen , +.\" +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH LIBSEXPR SECTION "November 24, 2014" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +libsexpr \- program to do something +.SH SYNOPSIS +.B libsexpr +.RI [ options ] " files" ... +.br +.B bar +.RI [ options ] " files" ... +.SH DESCRIPTION +This manual page documents briefly the +.B libsexpr +and +.B bar +commands. +.PP +.\" TeX users may be more comfortable with the \fB\fP and +.\" \fI\fP escape sequences to invode bold face and italics, +.\" respectively. +\fBlibsexpr\fP is a program that... +.SH OPTIONS +These programs follow the usual GNU command line syntax, with long +options starting with two dashes (`-'). +A summary of options is included below. +For a complete description, see the Info files. +.TP +.B \-h, \-\-help +Show summary of options. +.TP +.B \-v, \-\-version +Show version of program. +.SH SEE ALSO +.BR bar (1), +.BR baz (1). +.br +The programs are documented fully by +.IR "The Rise and Fall of a Fooish Bar" , +available via the Info system. diff --git a/debian/manpage.sgml.ex b/debian/manpage.sgml.ex new file mode 100644 index 0000000..4e2f586 --- /dev/null +++ b/debian/manpage.sgml.ex @@ -0,0 +1,154 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + + + The docbook-to-man binary is found in the docbook-to-man package. + Please remember that if you create the nroff version in one of the + debian/rules file targets (such as build), you will need to include + docbook-to-man in your Build-Depends control field. + + --> + + + FIRSTNAME"> + SURNAME"> + + November 24, 2014"> + + SECTION"> + vdo@daze"> + + LIBSEXPR"> + + + Debian"> + GNU"> + GPL"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2003 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + program to do something + + + + &dhpackage; + + + + + + + + DESCRIPTION + + This manual page documents briefly the + &dhpackage; and bar + commands. + + This manual page was written for the &debian; distribution + because the original program does not have a manual page. + Instead, it has documentation in the &gnu; + Info format; see below. + + &dhpackage; is a program that... + + + + OPTIONS + + These programs follow the usual &gnu; command line syntax, + with long options starting with two dashes (`-'). A summary of + options is included below. For a complete description, see the + Info files. + + + + + + + + Show summary of options. + + + + + + + + Show version of program. + + + + + + SEE ALSO + + bar (1), baz (1). + + The programs are documented fully by The Rise and + Fall of a Fooish Bar available via the + Info system. + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (and may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the &gnu; General Public License, Version 2 any + later version published by the Free Software Foundation. + + + On Debian systems, the complete text of the GNU General Public + License can be found in /usr/share/common-licenses/GPL. + + + +
+ + diff --git a/debian/manpage.xml.ex b/debian/manpage.xml.ex new file mode 100644 index 0000000..6224138 --- /dev/null +++ b/debian/manpage.xml.ex @@ -0,0 +1,291 @@ + +.
will be generated. You may view the +manual page with: nroff -man .
| less'. A typical entry +in a Makefile or Makefile.am is: + +DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl +XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" + +manpage.1: manpage.xml + $(XP) $(DB2MAN) $< + +The xsltproc binary is found in the xsltproc package. The XSL files are in +docbook-xsl. A description of the parameters you can use can be found in the +docbook-xsl-doc-* packages. Please remember that if you create the nroff +version in one of the debian/rules file targets (such as build), you will need +to include xsltproc and docbook-xsl in your Build-Depends control field. +Alternatively use the xmlto command/package. That will also automatically +pull in xsltproc and docbook-xsl. + +Notes for using docbook2x: docbook2x-man does not automatically create the +AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as + ... . + +To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections +read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be +found in the docbook-xsl-doc-html package. + +Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` + +General documentation about man-pages and man-page-formatting: +man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ + +--> + + + + + + + + + + + + + +]> + + + + &dhtitle; + &dhpackage; + + + &dhfirstname; + &dhsurname; + Wrote this manpage for the Debian system. +
+ &dhemail; +
+
+
+ + 2007 + &dhusername; + + + This manual page was written for the Debian system + (and may be used by others). + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU General Public License, + Version 2 or (at your option) any later version published by + the Free Software Foundation. + On Debian systems, the complete text of the GNU General Public + License can be found in + /usr/share/common-licenses/GPL. + +
+ + &dhucpackage; + &dhsection; + + + &dhpackage; + program to do something + + + + &dhpackage; + + + + + + + + + this + + + + + + + + this + that + + + + + &dhpackage; + + + + + + + + + + + + + + + + + + + DESCRIPTION + This manual page documents briefly the + &dhpackage; and bar + commands. + This manual page was written for the Debian distribution + because the original program does not have a manual page. + Instead, it has documentation in the GNU + info + 1 + format; see below. + &dhpackage; is a program that... + + + OPTIONS + The program follows the usual GNU command line syntax, + with long options starting with two dashes (`-'). A summary of + options is included below. For a complete description, see the + + info + 1 + files. + + + + + + + Does this and that. + + + + + + + Show summary of options. + + + + + + + Show version of program. + + + + + + FILES + + + /etc/foo.conf + + The system-wide configuration file to control the + behaviour of &dhpackage;. See + + foo.conf + 5 + for further details. + + + + ${HOME}/.foo.conf + + The per-user configuration file to control the + behaviour of &dhpackage;. See + + foo.conf + 5 + for further details. + + + + + + ENVIRONMENT + + + FOO_CONF + + If used, the defined file is used as configuration + file (see also ). + + + + + + DIAGNOSTICS + The following diagnostics may be issued + on stderr: + + + Bad configuration file. Exiting. + + The configuration file seems to contain a broken configuration + line. Use the option, to get more info. + + + + + &dhpackage; provides some return codes, that can + be used in scripts: + + Code + Diagnostic + + 0 + Program exited successfully. + + + 1 + The configuration file seems to be broken. + + + + + + BUGS + The program is currently limited to only work + with the foobar library. + The upstreams BTS can be found + at . + + + SEE ALSO + + + bar + 1 + , + baz + 1 + , + foo.conf + 5 + + The programs are documented fully by The Rise and + Fall of a Fooish Bar available via the + info + 1 + system. + +
+ diff --git a/debian/menu.ex b/debian/menu.ex new file mode 100644 index 0000000..697d325 --- /dev/null +++ b/debian/menu.ex @@ -0,0 +1,2 @@ +?package(libsexpr):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\ + title="libsexpr" command="/usr/bin/libsexpr" diff --git a/debian/postinst.ex b/debian/postinst.ex new file mode 100644 index 0000000..8c06adb --- /dev/null +++ b/debian/postinst.ex @@ -0,0 +1,39 @@ +#!/bin/sh +# postinst script for libsexpr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/postrm.ex b/debian/postrm.ex new file mode 100644 index 0000000..7fe16b1 --- /dev/null +++ b/debian/postrm.ex @@ -0,0 +1,37 @@ +#!/bin/sh +# postrm script for libsexpr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/preinst.ex b/debian/preinst.ex new file mode 100644 index 0000000..26b89a0 --- /dev/null +++ b/debian/preinst.ex @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for libsexpr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/prerm.ex b/debian/prerm.ex new file mode 100644 index 0000000..7b604d7 --- /dev/null +++ b/debian/prerm.ex @@ -0,0 +1,38 @@ +#!/bin/sh +# prerm script for libsexpr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove|upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..312e24d --- /dev/null +++ b/debian/rules @@ -0,0 +1,13 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +%: + dh $@ --with autotools-dev diff --git a/debian/shlibs.local.ex b/debian/shlibs.local.ex new file mode 100644 index 0000000..da0d48a --- /dev/null +++ b/debian/shlibs.local.ex @@ -0,0 +1 @@ +liblibsexpr 1.2 libsexpr (>> 1.2-0), libsexpr (<< 1.2-99) diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/watch.ex b/debian/watch.ex new file mode 100644 index 0000000..af1f385 --- /dev/null +++ b/debian/watch.ex @@ -0,0 +1,23 @@ +# Example watch control file for uscan +# Rename this file to "watch" and then you can run the "uscan" command +# to check for upstream updates and more. +# See uscan(1) for format + +# Compulsory line, this is a version 3 file +version=3 + +# Uncomment to examine a Webpage +# +#http://www.example.com/downloads.php libsexpr-(.*)\.tar\.gz + +# Uncomment to examine a Webserver directory +#http://www.example.com/pub/libsexpr-(.*)\.tar\.gz + +# Uncommment to examine a FTP server +#ftp://ftp.example.com/pub/libsexpr-(.*)\.tar\.gz debian uupdate + +# Uncomment to find new files on sourceforge, for devscripts >= 2.9 +# http://sf.net/libsexpr/libsexpr-(.*)\.tar\.gz + +# Uncomment to find new files on GooglePages +# http://example.googlepages.com/foo.html libsexpr-(.*)\.tar\.gz diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..e69de29 diff --git a/examples/TODO b/examples/TODO new file mode 100644 index 0000000..e69de29 diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..6b6500d --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,2 @@ +nobase_include_HEADERS = sexpr/cstring.h sexpr/faststack.h sexpr/sexp_errors.h \ + sexpr/sexp.h sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h diff --git a/include/sexpr/cstring.h b/include/sexpr/cstring.h new file mode 100644 index 0000000..30ca805 --- /dev/null +++ b/include/sexpr/cstring.h @@ -0,0 +1,146 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * cstring.h : c string library to make Ron happy. Wrapper around plain + * C strings that handles automatically growing the string as data is + * concattenated to the end. (note: this is an improved version of cstring + * from supermon. Migrate it into that library eventually... ) + * + * -matt sottile + */ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ +#ifndef __CSTRING_H__ +#define __CSTRING_H__ + +#include + +/** + * Structure wrapping the character pointer and size counters (allocated vs. + * actual used). + */ +typedef struct __cstring { + /** + * Base address of the string. + */ + char *base; + + /** + * Size of the memory allocated and pointed to by the base pointer. + */ + size_t len; + + /** + * Current size of the string stored in the buffer. len >= curlen + * always, and when len < curlen would be true after a concat operation, + * we realloc bigger space to keep len >= curlen. + */ + size_t curlen; +} CSTRING; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /** + * Set the growth size. Values less than one are ignored. + */ + void sgrowsize(size_t s); + + /** + * Allocate a new CSTRING of the given size. + * A NULL return value indicates that something went wrong and that + * sexp_errno should be checked for the cause. + */ + CSTRING *snew(size_t s); + + /** + * Concatenate the second argument to the CSTRING passed in the first. + * The second argument must be a pointer to a null terminated string. + * A NULL return value indicates that something went wrong and that + * sexp_errno should be checked for the cause. The contents of s are + * left alone. As such, the caller should check the pointer returned + * before overwriting the value of s, as this may result in a memory + * leak if an error condition occurs. + */ + CSTRING *sadd(CSTRING *s, char *a); + + /** + * Append a character to the end of the CSTRING. + * A NULL return value indicates that something went wrong and that + * sexp_errno should be checked for the cause. The contents of s are + * left alone. As such, the caller should check the pointer returned + * before overwriting the value of s, as this may result in a memory + * leak if an error condition occurs. + */ + CSTRING *saddch(CSTRING *s, char a); + + /** + * Trim the allocated memory to precisely the string length plus one char + * to hold the null terminator + * A NULL return value indicates that something went wrong and that + * sexp_errno should be checked for the cause. The contents of s are + * left alone. As such, the caller should check the pointer returned + * before overwriting the value of s, as this may result in a memory + * leak if an error condition occurs. + */ + CSTRING *strim(CSTRING *s); + + /** + * Return the base pointer of the CSTRING. NULL either means the base + * pointer was null, or the CSTRING itself was NULL. + */ + char *toCharPtr(CSTRING *s); + + /** + * Set the current length to zero, effectively dumping the string without + * deallocating it so we can use it later without reallocating any memory. + */ + void sempty(CSTRING *s); + + /** + * Destroy the CSTRING struct and the data it points at. + */ + void sdestroy(CSTRING *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CSTRING_H__ */ diff --git a/include/sexpr/faststack.h b/include/sexpr/faststack.h new file mode 100644 index 0000000..120beb2 --- /dev/null +++ b/include/sexpr/faststack.h @@ -0,0 +1,157 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * \file faststack.h + * + * \brief Implementation of a fast stack with smart memory management. + */ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ +#ifndef __FASTSTACK_H__ +#define __FASTSTACK_H__ + +/** + * Structure representing a single level in the stack. Has a pointer to the + * level above and below itself and a pointer to a generic blob of data + * associated with this level. + */ +typedef struct stack_level { + /** + * Pointer to the level above this one. If NULL, then this level is the + * top of the stack. If above is non-NULL, this level *may* be the top, + * but all that can be guaranteed is that there are other allocated + * but potentially unused levels above this one. + */ + struct stack_level *above; + + /** + * Pointer to the level below this one. If NULL, then this level is the + * bottom. + */ + struct stack_level *below; + + /** + * Pointer to some data associated with this level. User is responsible + * for knowing what to cast the \c void \c * pointer into. + */ + void *data; +} stack_lvl_t; + +/** + * Wrapper around the stack levels - keeps a pointer to the current top and + * bottom of the stack and a count of the current height. This allows the top + * to have non-null above pointer resulting from previously allocated stack + * levels that may be recycled later without \c malloc overhead. + */ +typedef struct stack_wrapper { + /** + * The top of the stack. If this is NULL, the stack is empty. + */ + stack_lvl_t *top; + + /** + * The bottom of the stack. If this is NULL, the stack is empty. + */ + stack_lvl_t *bottom; + + /** + * The current height of the stack, in terms of allocated and used levels. + */ + int height; +} faststack_t; + +/** functions **/ + +/* this is for C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Return a pointer to an empty stack structure. If the return value is + * NULL, one should check sexp_errno to determine why. + */ + faststack_t *make_stack(void); + + /** + * Given a stack structure, destroy it and free all of the stack levels. + * Important note : This function does not free the data + * pointed to from each level of the stack - the user is responsible + * for freeing this data themselves before calling this function to + * prevent memory leakage. + */ + void destroy_stack(faststack_t *s); + + /** + * Given a stack, push a new level on referring to the data pointer. + * If a new level cannot be allocated, NULL is returned and sexp_errno + * is set with the appropriate error condition. Memory allocation errors + * will result in SEXP_ERR_MEMORY, while a null stack will result in + * SEXP_ERR_BAD_STACK. + */ + faststack_t *push(faststack_t *cur_stack, void *data); + + /** + * Given a stack, pop a level off and return a pointer to that level. + * The user is responsible for extracting the data, but the stack_lvl_t + * structures pointed to from the level (above and below) should be left + * alone. If NULL is returned, either the stack contained nothing, or + * the incoming stack s was NULL. Consult sexp_errno to determine which + * was the case -- SEXP_ERR_BAD_STACK indicates a null stack was passed in. + */ + stack_lvl_t *pop(faststack_t *s); + +/* this is for C++ */ +#ifdef __cplusplus +} +#endif + +/** + * Given a stack \a s, examine the data pointer at the top. + */ +#define top_data(s) (s->top->data) + +/** + * Given a stack \a s, check to see if the stack is empty or not. Value + * is boolean true or false. + */ +#define empty_stack(s) (s->top == NULL) + +#endif /* __FASTSTACK_H__ */ diff --git a/include/sexpr/sexp.h b/include/sexpr/sexp.h new file mode 100644 index 0000000..46b8701 --- /dev/null +++ b/include/sexpr/sexp.h @@ -0,0 +1,771 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#ifndef __SEXP_H__ +#define __SEXP_H__ + +#include +#include /* for BUFSIZ only */ + +/* local includes */ +#include +#include +#include +#include +/* doxygen documentation groups defined here */ + +/** + * \defgroup IO I/O routines + */ + +/** + * \defgroup parser Parser routines + */ + +/** + * \mainpage A small and quick S-expression parsing library. + * + * \section intro Introduction + * + * This library was created to provide s-expression parsing and manipulation + * facilities to C and C++ programs. The primary goals were speed and + * efficiency - low memory impact, and the highest speed we could achieve in + * parsing. Suprisingly, no other libraries on the net were found that were + * not bloated with features or involved embedding a full-fledged LISP or + * Scheme interpreter into our programs. So, this library evolved to fill + * this gap. As such, it does not guarantee that every valid LISP + * expression is parseable, and many features that are not required aren't + * implemented. See Rivest's S-expression library for an example of a much + * more featureful library. + * + * What features does this library include? At the heart of the code is a + * continuation-based parser implementing a basic parser state machine. + * Continuations allow users to accumulate multiple streams of characters, + * and parse each stream simultaneously. A continuation allows the parser + * to stop midstream, start working on a new expression, and return to the + * first without corruption of complex state management in the users code. + * No threads, no forking, nothing more than a data structure that must be + * passed in and captured as data becomes available to parse. Once an + * expression has been parsed, a simple structure is returned that + * represents the "abstract syntax tree" of the parsed expression. For the + * majority of users, the parser and this data structure will be all that + * they will ever need to see. For convenience reasons, other functions + * such as I/O wrappers and AST traversal routines have been included, but + * they are not required if users don't wish to use them. + * + * \section credits Credits + * + * SFSEXP: Small, Fast S-Expression Library version 1.2, October 2007 \n + * Written by Matthew Sottile (matt@cs.uoregon.edu) + * + * \section license License Information + * + * Copyright (2003-2006). The Regents of the University of California. This + * material was produced under U.S. Government contract W-7405-ENG-36 for Los + * Alamos National Laboratory, which is operated by the University of + * California for the U.S. Department of Energy. The U.S. Government has rights + * to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR + * THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY + * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce + * derivative works, such modified software should be clearly marked, so as not + * to confuse it with the version available from LANL. + * + * Additionally, this library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + * + * LA-CC-04-094 + * + */ + +/** + * \file sexp.h + * + * \brief API for a small, fast and portable s-expression parser library. + */ + +/*==============*/ +/* ENUMERATIONS */ +/*==============*/ + +/** + * An element in an s-expression can be one of three types: a value + * represents an atom with an associated text value. A list + * represents an s-expression, and the element contains a pointer to + * the head element of the associated s-expression. + */ +typedef enum { + /** + * An atom of some type. See atom type (aty) field of element structure + * for details as to which atom type this is. + */ + SEXP_VALUE, + + /** + * A list. This means the element points to an element representing the + * head of a list. + */ + SEXP_LIST +} elt_t; + +/** + * For an element that represents a value, the value can be interpreted + * as a more specific type. A basic value is a simple string with + * no whitespace (and therefore no quotes required). A double quote + * value, or dquote, is one that contains characters (such as + * whitespace) that requires quotation marks to contain the string. A + * single quote value, or squote, represents an element that is + * prefaced with a single tick-mark. This can be either an atom or + * s-expression, and the result is that the parser does not attempt to parse + * the element following the tick mark. It is simply stored as text. This + * is similar to the meaning of a tick mark in the Scheme or LISP family + * of programming languages. Finally, binary allows raw binary to + * be stored within an atom. Note that if the binary type is used, the data + * is stored in bindata with the length in binlength. Otherwise, the data + * us stored in the val field with val_used and val_allocated tracking the + * size of the value string and the total memory allocated for it. + */ +typedef enum { + /** + * Basic, unquoted value. + */ + SEXP_BASIC, + + /** + * Single quote (tick-mark) value - contains a string representing + * a non-parsed portion of the s-expression. + */ + SEXP_SQUOTE, + + /** + * Double-quoted string. Similar to a basic value, but potentially + * containing white-space. + */ + SEXP_DQUOTE, + + /** + * Binary data. This is used when the specialized parser is active + * and supports inlining of binary blobs of data inside an expression. + */ + SEXP_BINARY +} atom_t; + +/*============*/ +/* STRUCTURES */ +/*============*/ + +/** + * An s-expression is represented as a linked structure of elements, + * where each element is either an atom or list. An + * atom corresponds to a string, while a list corresponds to an + * s-expression. The following grammar represents our definition of + * an s-expression:

+ * + *

+ * sexpr  ::= ( sx )
+ * sx     ::= atom sxtail | sexpr sxtail | 'sexpr sxtail | 'atom sxtail | NULL
+ * sxtail ::= sx | NULL
+ * atom   ::= quoted | value
+ * quoted ::= "ws_string"
+ * value  ::= nws_string
+ * 
+ *

+ * + * An atom can either be a quoted string, which is a string containing + * whitespace (possibly) surrounded by double quotes, or a non-whitespace + * string that does not require surrounding quotes. An element representing + * an atom will have a type of value and data stored in the val + * field. An element of type list represents an s-expression + * corresponding to sexpr in the grammar, and will have a pointer to + * the head of the appropriate s-expression. Details regarding these fields + * and their values given with the fields themselves. Notice that a single + * quote can appear directly before an s-expression or atom, similar to the + * use in LISP. + */ +typedef struct elt { + /** + * The element has a type that determines how the structure is used. + * If the type is SEXP_VALUE, then a programmer knows that + * either the val field or bindata field is meaningful dependin on + * the value of the aty field, and contains the data associated with + * this element of the s-expression. If the type is + * SEXP_LIST, then the list field contains a pointer to the + * s-expression element representing the head of the list. For each + * case, the field for the opposite case contains no meaningful data + * and using them in any way is likely to cause an error. + */ + elt_t ty; + + /** + * If the type of the element is SEXP_VALUE and the aty field + * is not SEXP_BINARY, this field will contain the actual data + * represented by this element. + */ + char *val; + + /** + * Number of bytes allocated for val. + */ + size_t val_allocated; + + /** + * Number of bytes used in val (<= val_allocated). + */ + size_t val_used; + + /** + * If the type of the element is SEXP_LIST, this field will contain + * a pointer to the head element of the list. + */ + struct elt *list; + + /** + * The next field is a pointer to the next element in the current + * expression. If this element is the last element in the s-expression, + * this field will be NULL. + */ + struct elt *next; + + /** + * For elements that represent values, this field will specify the + * specific type of value that it represents. This can be used by + * functions to determine how this value should be printed (ie: how it + * should be quoted) or interpreted (ie: interpreting s-expressions that + * are prefixed with a tick-mark.). This value also indicates whether or + * not the programmer should look in the val field or bindata field for + * the atom data. + */ + atom_t aty; + + /** + * For elements that represent binary blobs, this field will + * point to a memory location where the data resides. The length + * of this memory blob is the next field. char* implies byte sized + * elements. This is only used in INLINE_BINARY parser mode. + * IMPORTANT NOTE: The data in this field is freed on a + * destroy_sexp() call, so users should copy it to memory they allocate + * if they wish it to persist after the sexp_t has been freed. + */ + char *bindata; + + /** + * The length of the data pointed at by bindata in bytes. + */ + size_t binlength; +} sexp_t; + +/** + * parser mode flag used by continuation to toggle special parser + * behaviour. + */ +typedef enum { + /** + * normal (LISP-style) s-expression parser behaviour. + */ + PARSER_NORMAL, + + /** + * treat atoms beginning with \#b\# as inlined binary data. everything + * else is treated the same as in PARSER_NORMAL mode. + */ + PARSER_INLINE_BINARY, + + /** + * if the event_handlers field in the continuation contains a non-null + * value, the handlers specified in the parser_event_handlers_t struct + * will be called as appropriate, but the parser will not allocate a + * structure composed of sexp_t structs. Note that if the event_handlers + * is set to null and this mode is selected, the user would be better off + * not calling anything in the first place, as they are telling the parser + * to walk the string, but do nothing productive in the process. + */ + PARSER_EVENTS_ONLY +} parsermode_t; + +/** + * Some users would prefer to, instead of parsing a full string and walking + * a potentially huge sexp_t structure, use an XML SAX-style parser where + * events are triggered as certain parts of the s-expression are encountered. + * This structure contains a set of function pointers that are called by + * the parser as it hits expression start and end, and completes reading + * atoms and binary data. NOTE: The parser_event_handler struct that is + * a field in the continuation data structure is NOT freed by + * destroy_continuation since structs for callbacks are ALWAYS malloc'd + * by the user, not the library. + */ +typedef struct parser_event_handlers { + /** + * The start_sexpr function pointer is called when an open parenthesis + * is encountered starting an expression. + */ + void (* start_sexpr)(void); + + /** + * The end_sexpr function pointer is called when an close parenthesis + * is encountered ending an expression. + */ + void (* end_sexpr)(void); + + /** + * The characters function pointer is called when an atom is completely + * parsed. The function must take three arguments: a pointer to the + * atom data, the number of elements the atom contains, and the + * specific type of atom that the data represents. + */ + void (* characters)(const char *data, size_t len, atom_t aty); + + /** + * The binary function pointer is called when the parser is functioning + * in INLINE_BINARY mode and binary data is encountered. The function + * must take two arguments: a pointer to the beginning of the binary data + * and the number of bytes of data present. + */ + void (* binary)(const char *data, size_t len); +} parser_event_handlers_t; + +/** + * A continuation is used by the parser to save and restore state between + * invocations to support partial parsing of strings. For example, if we + * pass the string "(foo bar)(goo car)" to the parser, we want to be able + * to retrieve each s-expression one at a time - it would be difficult to + * return all s-expressions at once without knowing how many there are in + * advance (this would require more memory management than we want...). + * So, by using a continuation-based parser, we can call it with this string + * and have it return a continuation when it has parsed the first + * s-expression. Once we have processed the s-expression (accessible + * through the last_sexpr field of the continuation), we can call + * the parser again with the same string and continuation, and it will be + * able to pick up where it left off.

+ * + * We use continuations instead of a state-ful parser to allow multiple + * concurrent strings to be parsed by simply maintaining a set of + * continuations. Manipulating continuations by hand is required if the + * continuation-based parser is called directly. This is not + * recommended unless you are willing to deal with potential errors and + * are willing to learn exactly how the continuation relates to the + * internals of the parser. A simpler approach is to use either the + * parse_sexp function that simply returns an s-expression without + * exposing the continuations, or the iparse_sexp function that + * allows iteratively popping one s-expression at a time from a string + * containing one or more s-expressions. Refer to the documentation for + * each parsing function for further details on behavior and usage. + */ +typedef struct pcont { + /** + * The parser stack used for iterative parsing. + */ + faststack_t *stack; + + /** + * The last full s-expression encountered by the parser. If this is + * NULL, the parser has not encountered a full s-expression and more + * data is required for the current s-expression being parsed. If this + * is non-NULL, then the parser has encountered one s-expression and may + * be partially through parsing the next s-expression. + */ + sexp_t *last_sexp; + + /** + * Pointer to a temporary buffer used to store atom values during parsing. + */ + char *val; + + /** + * Current number of bytes allocated for val. + */ + size_t val_allocated; + + /** + * Current number of used bytes in val. + */ + size_t val_used; + + /** + * Pointer to the character following the last character in the current + * atom value being parsed. + */ + char *vcur; + + /** + * Pointer to the last character to examine in the string being parsed. + * When the parser is called with the continuation, this is the first + * character that will be processed. If this is NULL, the parser will + * start parsing at the beginning of the string passed into the parser. + */ + char *lastPos; + + /** + * This is a pointer to the beginning of the current string being + * processed. lastPos is a pointer to some value inside the string + * that this points to. + */ + char *sbuffer; + + /** + * This is the depth of parenthesis (the number of left parens encountered) + * that the parser is currently working with. + */ + unsigned int depth; + + /** + * This is the depth of parenthesis encountered after a single quote (tick) + * if the character immediately following the tick was a left paren. + */ + unsigned int qdepth; + + /** + * This is the state ID of the current state of the parser in the + * DFA representing the parser. The current parser is a DFA based parser + * to simplify restoring the proper state from a continuation. + */ + unsigned int state; + + /** + * This is a flag indicating whether the next character to be processed + * should be assumed to have been prefaced with a '\' character to escape + * it. + */ + unsigned int esc; + + /** + * Flag whether or not we are processing an atom that was preceeded by + * a single quote. + */ + unsigned int squoted; + + /** + * Error code. Used to indicate that the continuation being returned does + * not represent a successful parsing and thus the contents aren't of much + * value. + */ + sexp_errcode_t error; + + /** + * Mode. The parsers' specialized behaviours can be activated by + * tweaking the mode setting. There are currently two available: + * normal and inline_binary. Inline_binary treats atoms that start + * with \#b\# specially, assuming that they have the structure: + * + * \#b\#s\#data + * + * Where s is a positive (greater than 0) integer representing the length + * of the data, and data is s bytes of binary data following the \# + * sign. After the s bytes, it is assumed normal s-expression data + * continues. + */ + parsermode_t mode; + + /* ----------------------------------------------------------------- + * These fields below are related to dealing with INLINE_BINARY mode + * ----------------------------------------------------------------- */ + + /** + * Length to expect of the current binary data being read in. + * this also corresponds to the size of the memory allocated for + * reading this binary data into. + */ + size_t binexpected; + + /** + * Number of bytes of the binary blob that have already been read in. + */ + size_t binread; + + /** + * Pointer to the memory containing the binary data being read in. + */ + char *bindata; + + /** + * Pointer to a structure holding handlers for sexpr events. NULL for + * normal parser operation. This field is NOT freed by + * destroy_continuation and must be free'd by the user. This is because + * these are malloc'd outside the library ALWAYS, so they are the user's + * responsibility. + */ + parser_event_handlers_t *event_handlers; +} pcont_t; + +/** + * \ingroup IO + * This structure is a wrapper around a standard I/O file descriptor and + * the parsing infrastructure (continuation and a buffer) required to + * parse off of it. This is used so that routines can hide the loops and + * details required to accumulate up data read off of the file descriptor + * and parse expressions individually out of it. + */ +typedef struct sexp_iowrap { + /** + * Continuation used to parse off of the file descriptor. + */ + pcont_t *cc; + + /** + * The file descriptor. Currently CANNOT be a socket since implementation + * uses read(), not recv(). + */ + int fd; + + /** + * Buffer to read data into before parsing. + */ + char buf[BUFSIZ]; + + /** + * Byte count for last read. If it is -1, there was an error. Otherwise, + * it will be a value from 0 to BUFSIZ. + */ + int cnt; +} sexp_iowrap_t; + +/*========*/ +/* GLOBAL */ +/*========*/ + +/** + * Global value indicating the most recent error condition encountered. + * This value can be reset to SEXP_ERR_OK by calling sexp_errno_reset(). + */ +extern sexp_errcode_t sexp_errno; + +/*===========*/ +/* FUNCTIONS */ +/*===========*/ + +/* this is for C++ users */ +#ifdef __cplusplus +extern "C" { +#endif + /** + * \ingroup parser + * Set the parameters on atom value buffer allocation and growth sizes. + * This is an important point for performance tuning, as many factors in + * the expected expression structure must be taken into account such as: + * + * - Average size of atom values + * - Variance in sizes of atom values + * - Amount of memory that is tolerably ''wasted'' (allocated but not + * used) + * + * The \a ss parameter specifies the initial size of all atom buffers. + * Ideally, this should be sufficiently large to capture MOST atom values, + * or at least close enough such that one growth is required. The + * \a gs parameter specifies the number of bytes to increase the buffer size + * by when space is exhausted. A safe choice for parameter sizes would + * be on the order of the average size for \a ss, and one standard + * deviation for \a gs. This ensures that 50% of all expressions are + * guaranteed to fit in the initial buffer, and rougly 80-90% will fit in + * one growth. If memory is not an issue, choosing ss to be the mean plus + * one standard deviation will capture 80-90% of expressions in the initial + * buffer, and a gs of one standard deviation will capture nearly all + * expressions. + * + * Note: These parameters can be tuned at runtime as needs change, and they + * will be applied to all expressions and expression elements parsed after + * they are modified. They will not be applied retroactively to expressions + * that have already been parsed. + */ + sexp_errcode_t set_parser_buffer_params(size_t ss, size_t gs); + + /** + * return an allocated sexp_t. This structure may be an already allocated + * one from the stack or a new one if none are available. Use this instead + * of manually mallocing if you want to avoid excessive mallocs. Note: + * Mallocing your own expressions is fine - you can even use + * sexp_t_deallocate to deallocate them and put them in the pool. + * Also, if the stack has not been initialized yet, this does so. + */ + sexp_t *sexp_t_allocate(void); + + /** + * given a malloc'd sexp_t element, put it back into the already-allocated + * element stack. This method will allocate a stack if one has not been + * allocated already. + */ + void sexp_t_deallocate(sexp_t *s); + + /** + * In the event that someone wants us to release ALL of the memory used + * between calls by the library, they can free it. If you don't call + * this, the caches will be persistent for the lifetime of the library + * user. Note that in the event of an error condition resulting in + * sexp_errno being set, the user might consider calling this to clean up + * any memory that may be lingering around that should be cleaned up. + */ + void sexp_cleanup(void); + + /** + * print a sexp_t struct as a string in the LISP style. If the buffer + * is large enough and the conversion is successful, the return value + * represents the length of the string contained in the buffer. If the + * buffer was too small, or some other error occurred, the return + * value is -1 and the contents of the buffer should not be assumed to + * contain any useful information. When the return value is -1, the + * caller should check the contents of sexp_errno for details on what + * error may have occurred. + */ + int print_sexp(char *loc, size_t size, const sexp_t *e); + + /** + * print a sexp_t structure to a buffer, growing it as necessary instead + * of relying on fixed size buffers like print_sexp. Important argument + * to tune for performance reasons is ss - the + * buffer start size. The growsize used by the CSTRING routines also should + * be considered for tuning via the sgrowsize() function. This routine no + * longer requires the user to specify the growsize, and uses the current + * setting without changing it. + */ + int print_sexp_cstr(CSTRING **s, const sexp_t *e, size_t ss); + + /** + * Allocate a new sexp_t element representing a list. + */ + sexp_t *new_sexp_list(sexp_t *l); + + /** + * Allocate a new sexp_t element representing a value. The user must + * specify the precise type of the atom. This used to default to + * SEXP_BASIC, but this can lead to errors if the user did not expect this + * assumption. By explicitly passing in the atom type, the caller should + * ensure that the data in the buffer is valid given the requested atom + * type. For performance reasons, such checks are left to the caller if + * they are desired, and not performed in the library if they are not + * wanted. + */ + sexp_t *new_sexp_atom(const char *buf, size_t bs, atom_t aty); + + /** + * create an initial continuation for parsing the given string + */ + pcont_t *init_continuation(char *str); + + /** + * destroy a continuation. This involves cleaning up what it contains, + * and cleaning up the continuation itself. + */ + void destroy_continuation (pcont_t * pc); + + /** + * \ingroup IO + * create an IO wrapper structure around a file descriptor. A NULL return + * value indicates some problem occurred allocating the wrapper, so the + * user should check the value of sexp_errno for further information. + */ + sexp_iowrap_t *init_iowrap(int fd); + + /** + * \ingroup IO + * destroy an IO wrapper structure. The file descriptor wrapped in the + * wrapper will not be closed, so the caller is responsible + * for manually calling close on the file descriptor. + */ + void destroy_iowrap(sexp_iowrap_t *iow); + + /** + * \ingroup IO + * given and IO wrapper handle, read one s-expression + * off of it. this expression may be contained in a continuation, + * so there is no guarantee that under the covers an IO read + * actually is occuring. A return value of NULL can either indicate + * a parser error or no more data on the input IO handle. In the + * event that NULL is returned, the user should check to see if + * sexp_errno contains SEXP_ERR_IO_EMPTY (no more data) or a more + * problematic error. + */ + sexp_t *read_one_sexp(sexp_iowrap_t *iow); + + /** + * \ingroup parser + * wrapper around parser for compatibility. + */ + sexp_t *parse_sexp(char *s, size_t len); + + /** + * \ingroup parser + * wrapper around parser for friendlier continuation use + * pre-condition : continuation (cc) is NON-NULL! + */ + sexp_t *iparse_sexp(char *s, size_t len, pcont_t *cc); + + /** + * \ingroup parser + * given a LISP style s-expression string, parse it into a set of + * connected sexp_t structures. + */ + pcont_t *cparse_sexp(char *s, size_t len, pcont_t *pc); + + /** + * given a sexp_t structure, free the memory it uses (and recursively free + * the memory used by all sexp_t structures that it references). Note + * that this will call the deallocation routine for sexp_t elements. + * This means that memory isn't freed, but stored away in a cache of + * pre-allocated elements. This is an optimization to speed up the + * parser to eliminate wasteful free and re-malloc calls. Note: If using + * inlined binary mode, this will free the data pointed to by the bindata + * field. So, if you care about the data after the lifetime of the + * s-expression, make sure to make a copy before cleaning up the sexpr. + */ + void destroy_sexp(sexp_t *s); + + /** + * reset the value of sexp_errno to SEXP_ERR_OK. + */ + void reset_sexp_errno(void); + +/* this is for C++ users */ +#ifdef __cplusplus +} +#endif + +#include "sexp_ops.h" + +#endif /* __SEXP_H__ */ + diff --git a/include/sexpr/sexp_errors.h b/include/sexpr/sexp_errors.h new file mode 100644 index 0000000..b4bf11a --- /dev/null +++ b/include/sexpr/sexp_errors.h @@ -0,0 +1,139 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#ifndef __SEXP_ERRORS_H__ +#define __SEXP_ERRORS_H__ + +/** + * \file sexp_errors.h + * + * \brief Error conditions are enumerated here along with any routines for + * translating error codes to human readable messages. + */ + +/** + * Error codes used by the library are defined in this enumeration. They + * are either used as values for the error field within the continuation + * structures, or as return values for functions with a return type of + * sexp_errcode_t. + */ +typedef enum { + /** + * no error. + */ + SEXP_ERR_OK = 0, + + /** + * memory error. malloc/realloc/calloc failures may result in this error + * code. this can either result from the system calls failing, or in the + * limited memory mode of the library, the memory limit being exceeded. + * In limited memory mode, if this error condition is present, one should + * check the memory limits that were in place during the erroneous call. + */ + SEXP_ERR_MEMORY, + + /** + * badly formed expression. Missing, misplaced, or mismatched parenthesis + * will result in this error. + */ + SEXP_ERR_BADFORM, + + /** + * a sexp_t that is inconsistent will result in this error code. An example + * is a SEXP_BASIC sexp_t with a null val field but a non-zero val_used + * value. Similar cases exist for SEXP_DQUOTE, SQUOTE, and BINARY types. + * This value is also used in the parser to flag a case where an inlined + * binary block is given a negative length. + */ + SEXP_ERR_BADCONTENT, + + /** + * if a null string is passed into the parser, this error occurs. + */ + SEXP_ERR_NULLSTRING, + + /** + * general IO related errors, such as failure of fopen(). these are + * basically non-starters with respect to getting the IO routines going. + */ + SEXP_ERR_IO, + + /** + * I/O routines that return NULL may simply have nothing to read. This is + * sometimes an error condition if the io wrapper continuation contains a + * partially complete s-expression, but nothing more is present (yet) on the + * file descriptor. + */ + SEXP_ERR_IO_EMPTY, + + /** + * when running the library under limited memory (ie, _SEXP_LIMIT_MEMORY_ + * defined at build time), this error will be produced when the memory + * limit is exceeded. + */ + SEXP_ERR_MEM_LIMIT, + + /** + * buffer for unparsing is full. + */ + SEXP_ERR_BUFFER_FULL, + + /** + * routines that take parameters such as memory limits, growth sizes, or + * default sizes, can produce this error if a bad value has been passed in. + * this error usually will indicate that the parameters were bad and the + * default values were used instead (ie, it is non-fatal.). + */ + SEXP_ERR_BAD_PARAM, + + /** + * bad stack state encountered. + */ + SEXP_ERR_BAD_STACK, + + /** + * unknown parser state + */ + SEXP_ERR_UNKNOWN_STATE + +} sexp_errcode_t; + +#endif /* __SEXP_ERRORS_H__ */ diff --git a/include/sexpr/sexp_memory.h b/include/sexpr/sexp_memory.h new file mode 100644 index 0000000..18bb856 --- /dev/null +++ b/include/sexpr/sexp_memory.h @@ -0,0 +1,165 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#ifndef __SEXP_MEMORY_H__ +#define __SEXP_MEMORY_H__ + +/** + * \file sexp_memory.h + * + * \brief Wrappers around basic memory allocation/deallocation routines to + * allow memory usage limiting. Only enabled if _SEXP_LIMIT_MEMORY_ + * is defined when building the library, otherwise the routines + * are defined to be the standard malloc/calloc/realloc/free + * functions. + */ + + +#ifdef _SEXP_LIMIT_MEMORY_ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * \defgroup memory Memory management routines. + */ + + /** + * \ingroup memory + * Wrapper around malloc, will check and increment memory usage + * counters if space is available. Returns NULL if no memory left + * to use, otherwise returns whatever malloc returns. + * Due to the fact that NULL could mean either the memory limit was exceeded + * or the system call returned NULL, the user must check sexp_errno to + * determine the root cause. + */ + void *sexp_malloc(size_t size); + + /** + * \ingroup memory + * Wrapper around calloc, will check and increment memory usage + * counters if space is available. Returns NULL if no memory left + * to use, otherwise returns whatever calloc returns + * Due to the fact that NULL could mean either the memory limit was exceeded + * or the system call returned NULL, the user must check sexp_errno to + * determine the root cause. + */ + void *sexp_calloc(size_t count, size_t size); + + /** + * \ingroup memory + * Wrapper around free. Instead of trusting sizeof(ptr) to return the + * proper value, we explicitly pass the size of memory associated with + * ptr. Decrements memory usage counter and frees ptr. + */ + void sexp_free(void *ptr, size_t size); + + /** + * \ingroup memory + * Wrapper around realloc. Instead of trusting sizeof(ptr) to return the + * proper value, we explicitly pass the size of memory associated with + * ptr as the oldsize. Increments the memory usage counter by + * (size-oldsize) if enough space available for realloc. + * Returns NULL if no memory left to use, otherwise returns whatever + * realloc returns. + * Due to the fact that NULL could mean either the memory limit was exceeded + * or the system call returned NULL, the user must check sexp_errno to + * determine the root cause. + */ + void *sexp_realloc(void *ptr, size_t size, size_t oldsize); + + /** + * \ingroup memory + * Return the memory limit imposed by the library if memory limiting was + * enabled at compile time. + */ + size_t get_sexp_max_memory(); + + /** + * \ingroup memory + * Return the amount of memory used. + */ + size_t get_sexp_used_memory(); + + /** + * \ingroup memory + * Set the memory limit if memory limiting was enabled. If the new value + * is zero or less, -1 is returned and sexp_errno is set. Similarly, if + * the new value is less than the current amount used by the library, + * -1 is returned and sexp_errno is set. If the new value is valid, the + * new value is returned. + */ + int set_sexp_max_memory(size_t newsize); + +#ifdef __cplusplus +} +#endif + +#else + +/** + * \ingroup memory + * _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to calloc(). + */ +#define sexp_calloc(count,size) calloc(count,size) + +/** + * \ingroup memory + * _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to malloc(). + */ +#define sexp_malloc(size) malloc(size) + +/** + * \ingroup memory + * _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to free(). + */ +#define sexp_free(ptr,size) free(ptr) + +/** + * \ingroup memory + * _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to realloc(). + */ +#define sexp_realloc(ptr,size,oldsize) realloc((ptr),(size)) + +#endif + +#endif /* __SEXP_MEMORY_H__ */ diff --git a/include/sexpr/sexp_ops.h b/include/sexpr/sexp_ops.h new file mode 100644 index 0000000..e5049f0 --- /dev/null +++ b/include/sexpr/sexp_ops.h @@ -0,0 +1,138 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#ifndef __SEXP_OPS_H__ +#define __SEXP_OPS_H__ + +/** + * \file sexp_ops.h + * + * \brief A collection of useful operations to perform on s-expressions. + * + * A set of routines for operating on s-expressions. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /*========*/ + /* MACROS */ + /*========*/ + + /** + * Return the head of a list \a s by reference, not copy. + */ +#define hd_sexp(s) ((s)->list) + + /** + * Return the tail of a list \a s by reference, not copy. + */ +#define tl_sexp(s) ((s)->list->next) + + /** + * Return the element following the argument \a s. + */ +#define next_sexp(s) ((s)->next) + + /** + * Reset the continuation \a c by setting the \c lastPos pointer to + * \c NULL. + */ +#define reset_pcont(c) ((c)->lastPos = NULL) + + /** + * Find an atom in a sexpression data structure and return a pointer to + * it. Return NULL if the string doesn't occur anywhere as an atom. + * This is a depth-first search algorithm. + * + * \param name Value to search for. + * \param start Root element of the s-expression to search from. + * \return If the value is found, return a pointer to the first + * occurrence in a depth-first traversal. NULL if not found. + */ + sexp_t *find_sexp(const char *name, sexp_t *start); + + /** + * Breadth first search for s-expressions. Depth first search will find + * the first occurance of a string in an s-expression by basically finding + * the earliest occurance in the string representation of the expression + * itself. Breadth first search will find the first occurance of a string + * in relation to the structure of the expression itself (IE: the instance + * with the lowest depth will be found). + * + * \param name Value to search for. + * \param start Root element of the s-expression to search from. + * \return If the value is found, return a pointer to the first + * occurrence in a breadth-first traversal. NULL if not found. + */ + sexp_t *bfs_find_sexp(const char *name, sexp_t *start); + + /** + * Given an s-expression, determine the length of the list that it encodes. + * A null expression has length 0. An atom has length 1. A list has + * length equal to the number of sexp_t elements from the list head + * to the end of the ->next linked list from that point. + * + * \param sx S-expression input. + * \return Number of sexp_t elements at the same level as sx, 0 for + * NULL, 1 for an atom. + */ + int sexp_list_length(const sexp_t *sx); + + /** + * Copy an s-expression. This is a deep copy - so the resulting s-expression + * shares no pointers with the original. The new one can be changed without + * damaging the contents of the original. + * + * \param sx S-expression to copy. + * \return A pointer to a copy of sx. This is a deep copy, so no memory + * is shared between the original and the returned copy. + */ + sexp_t *copy_sexp(const sexp_t *sx); + +#ifdef __cplusplus +} +#endif + +#endif /* __SEXP_OPS_H__ */ diff --git a/include/sexpr/sexp_vis.h b/include/sexpr/sexp_vis.h new file mode 100644 index 0000000..b068360 --- /dev/null +++ b/include/sexpr/sexp_vis.h @@ -0,0 +1,69 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * \defgroup viz Visualization and debugging routines + */ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +/** + * \file sexp_vis.h + * + * \brief API for emitting graphviz data structure visualizations. + */ +#ifndef __SEXP_VIS_H__ +#define __SEXP_VIS_H__ + +/** + * \ingroup viz + * + * Given a s-expression and a filename, this routine creates a DOT-file that + * can be used to generate a visualization of the s-expression data structure. + * This is useful for debugging to ensure that the structure is correct and + * follows what was expected by the programmer. Non-trivial s-expressions + * can yield very large visualizations though. Sometimes it is more + * practical to visualize a portion of the structure if one knows where a bug + * is likely to occur. + * + * \param sx S-expression data structure to create a DOT file based on. + * \param fname Filename of the DOT file to emit. + */ +sexp_errcode_t sexp_to_dotfile(const sexp_t *sx, const char *fname); + +#endif /* __SEXP_VIS_H__ */ diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..648c27e --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ + -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ + $(LIBTDATA_CFLAGS) -I../include + +AM_CFLAGS =\ + -Wall\ + -g + +lib_LTLIBRARIES = libsexpr.la + + +libsexpr_la_SOURCES = \ + cstring.c event_temp.c faststack.c io.c \ + parser.c sexp.c sexp_memory.c sexp_ops.c sexp_vis.c + +libsexpr_la_LDFLAGS = + +libsexpr_la_LIBADD = + +##include_HEADERS = \ +## ../include/sexpr/cstring.h ../include/sexpr/faststack.h ../include/sexpr/sexp_errors.h \ +## ../include/sexpr/sexp.h ../include/sexpr/sexp_memory.h ../include/sexpr/sexp_ops.h \ +## ../include/sexpr/sexp_vis.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsexpr-1.2.pc + +EXTRA_DIST = \ + libsexpr-1.2.pc.in + diff --git a/lib/cstring.c b/lib/cstring.c new file mode 100644 index 0000000..c91a194 --- /dev/null +++ b/lib/cstring.c @@ -0,0 +1,225 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Implementation of stuff in cstring.h to make ron happy + */ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include +#include +#include +#include + +/** + * growth size for cstrings -- default is 8k. use sgrowsize() to adjust. + */ +static size_t cstring_growsize = 8192; + +void sgrowsize(size_t s) { + if (s < 1) + return; + + cstring_growsize = s; +} + +CSTRING *snew(size_t s) { + CSTRING *cs; + +#ifdef __cplusplus + cs = (CSTRING *)sexp_malloc(sizeof(CSTRING)); +#else + cs = sexp_malloc(sizeof(CSTRING)); +#endif + if (cs == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + cs->len = s; + cs->curlen = 0; + +#ifdef __cplusplus + cs->base = (char *)sexp_calloc(sizeof(char),s); +#else + cs->base = sexp_calloc(sizeof(char),s); +#endif + if (cs->base == NULL) { + sexp_free(cs,sizeof(CSTRING)); + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + return cs; +} + +CSTRING *sadd(CSTRING *s, char *a) { + int alen; + char *newbase; + + /* no string, so bail */ + if (s == NULL) { + return NULL; + } + + /* nothing to add, return s */ + if (a == NULL) { + return s; + } + + alen = strlen(a); + + if (s->curlen + alen >= s->len) { +#ifdef __cplusplus + newbase = (char *)sexp_realloc(s->base, + s->len+cstring_growsize+alen, + s->len); +#else + newbase = sexp_realloc(s->base, + s->len+cstring_growsize+alen, + s->len); +#endif + + /* do NOT destroy s anymore. if realloc fails, the original data is + still valid, so just report the error to sexp_errno and return NULL. + */ + if (newbase == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + s->len += cstring_growsize + alen; + s->base = newbase; + } + + memcpy(&s->base[s->curlen],a,alen); + s->curlen += alen; + s->base[s->curlen] = 0; + return s; +} + +CSTRING *saddch(CSTRING *s, char a) { + char *newbase; + + if (s == NULL) { + return NULL; + } + + if (s->curlen + 1 >= s->len) { +#ifdef __cplusplus + newbase = (char *)sexp_realloc(s->base, + s->len+cstring_growsize+1, + s->len); +#else + newbase = sexp_realloc(s->base, + s->len+cstring_growsize+1, + s->len); +#endif + + /* do NOT destroy s anymore. if realloc fails, the original data is + still valid, so just report the error to sexp_errno and return NULL. + */ + if (newbase == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + s->len += cstring_growsize+1; + s->base = newbase; + } + + s->base[s->curlen] = a; + s->curlen++; + s->base[s->curlen] = 0; + return s; +} + +CSTRING *strim(CSTRING *s) { + char *newbase; + + if (s == NULL) { + return NULL; + } + + /* no trimming necessary? */ + if (s->len == s->curlen+1) { + return s; + } + +#ifdef __cplusplus + newbase = (char *)sexp_realloc(s->base, + s->curlen+1, + s->len); +#else + newbase = sexp_realloc(s->base, + s->curlen+1, + s->len); +#endif + + /* do NOT destroy s anymore. if realloc fails, the original data is + still valid, so just report the error to sexp_errno and return NULL. + */ + if (newbase == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + s->len = s->curlen+1; + s->base = newbase; + + return s; +} + +char *toCharPtr(CSTRING *s) { + if (s == NULL) return NULL; + return s->base; +} + +void sempty(CSTRING *s) { + if (s == NULL) return; + s->curlen = 0; +} + +void sdestroy(CSTRING *s) { + if (s == NULL) return; + sexp_free(s->base,s->len); + sexp_free(s,sizeof(CSTRING)); +} diff --git a/lib/event_temp.c b/lib/event_temp.c new file mode 100644 index 0000000..e9734d1 --- /dev/null +++ b/lib/event_temp.c @@ -0,0 +1,896 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include + +static size_t sexp_val_start_size = 256; +static size_t sexp_val_grow_size = 64; + +/*************************************************************************/ + + +/** + * event parser : based on cparse_sexp from v1.91 of this file. separate out + * in the event that the parser mode is PARSER_EVENTS_ONLY. + */ +pcont_t * +eparse_sexp (char *str, size_t len, pcont_t *lc) +{ + char *t, *s; + register size_t binexpected = 0; + register size_t binread = 0; + register parsermode_t mode = PARSER_NORMAL; + register size_t val_allocated = 0; + register unsigned int squoted = 0; + register size_t val_used = 0; + register unsigned int state = 1; + register unsigned int depth = 0; + register unsigned int qdepth = 0; + register unsigned int elts = 0; + register unsigned int esc = 0; + pcont_t *cc; + char *val, *vcur, *bindata = NULL; + faststack_t *stack; + char *bufEnd; + int keepgoing = 1; + parser_event_handlers_t *event_handlers = NULL; + + /* make sure non-null string */ + if (str == NULL) { + lc->error = SEXP_ERR_NULLSTRING; + return lc; + } + + /* first, if we have a non null continuation passed in, restore state. */ + if (lc != NULL) { + cc = lc; + binexpected = cc->binexpected; + binread = cc->binread; + bindata = cc->bindata; + val_used = cc->val_used; + val_allocated = cc->val_allocated; + squoted = cc->squoted; + val = cc->val; + vcur = cc->vcur; + state = cc->state; + depth = cc->depth; + qdepth = cc->qdepth; + stack = cc->stack; + esc = cc->esc; + mode = cc->mode; + event_handlers = cc->event_handlers; + s = str; + if (cc->lastPos != NULL) + t = cc->lastPos; + else { + t = s; + cc->sbuffer = str; + } + } else { + /* new continuation... */ +#ifdef __cplusplus + cc = (pcont_t *)sexp_malloc(sizeof(pcont_t)); +#else + cc = sexp_malloc(sizeof(pcont_t)); +#endif + assert(cc != NULL); + + cc->mode = mode; + + /* allocate atom buffer */ +#ifdef __cplusplus + cc->val = val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size); +#else + cc->val = val = sexp_malloc(sizeof(char)*sexp_val_start_size); +#endif + assert(val != NULL); + + cc->val_used = val_used = 0; + cc->val_allocated = val_allocated = sexp_val_start_size; + + vcur = val; + + /* allocate stack */ + cc->stack = stack = make_stack(); + cc->bindata = NULL; + cc->binread = cc->binexpected = 0; + + /* event handlers are null */ + cc->event_handlers = NULL; + + /* t is temp pointer into s for current position */ + s = str; + t = s; + cc->sbuffer = str; + } + + bufEnd = cc->sbuffer+len; + + /* guard for loop - see end of loop for info. Put it out here in the + event that we're restoring state from a continuation and need to + check before we start up. */ + if (state != 15 && t[0] == '\0') keepgoing = 0; + + /*==================*/ + /* main parser loop */ + /*==================*/ + while (keepgoing == 1 && t != bufEnd) + { + + /* based on the current state in the FSM, do something */ + switch (state) + { + case 1: + switch (t[0]) + { + /* space,tab,CR,LF considered white space */ + case '\n': + case ' ': + case '\t': + case '\r': + t++; + break; + /* semicolon starts a comment that extends until a \n is + encountered. */ + case ';': + t++; + state = 11; + break; + /* enter state 2 for open paren */ + case '(': + state = 2; + t++; + if (event_handlers != NULL && + event_handlers->start_sexpr != NULL) + event_handlers->start_sexpr(); + break; + /* enter state 3 for close paren */ + case ')': + state = 3; + break; + /* begin quoted string - enter state 5 */ + case '\"': + state = 5; + /* set cur pointer to beginning of val buffer */ + vcur = val; + t++; + break; + /* single quote - enter state 7 */ + case '\'': + state = 7; + t++; + break; + /* other characters are assumed to be atom parts */ + default: + /* set cur pointer to beginning of val buffer */ + vcur = val; + + /** NOTE: the following code originally required a transition + to state 4 before processing the first atom character -- + this required two iterations for the first character + of each atom. merging this into here allows us to process + what we already know to be a valid atom character before + entering state 4. **/ + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + /* if the atom starts with # and we're in inline + binary mode, we need to go to state 12 to start + checking for the #b# prefix. otherwise, + if it's not a # or we're just in normal mode, + proceed to state 4 as usual. */ + if (t[0] == '#' && mode == PARSER_INLINE_BINARY) { + state = 12; + } else { + state = 4; + } + + t++; + break; + } + break; + case 2: + /* open paren */ + depth++; + + elts++; + + if (stack->height < 1) + stack->height++; + + stack->height++; + + state = 1; + break; + case 3: + /** close paren **/ + + /* check for close parens that were never opened. */ + if (depth == 0) { + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->val = val; + cc->mode = mode; + cc->val_used = val_used; + cc->val_allocated = val_allocated; + cc->vcur = vcur; + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->last_sexp = NULL; + cc->error = SEXP_ERR_BADFORM; + cc->event_handlers = event_handlers; + + return cc; + } + + t++; + depth--; + + stack->height--; + + if (event_handlers != NULL && + event_handlers->end_sexpr != NULL) + event_handlers->end_sexpr(); + + state = 1; + + /** if depth = 0 then we finished a sexpr, and we return **/ + if (depth == 0) { + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->error = SEXP_ERR_OK; + cc->mode = mode; + cc->val = val; + cc->val_allocated = val_allocated; + cc->val_used = val_used; + cc->vcur = vcur; + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->event_handlers = event_handlers; + cc->last_sexp = NULL; + stack->height = 0; + + return cc; + } + break; + case 4: /** parsing atom **/ + if (esc == 1 && (t[0] == '\"' || t[0] == '(' || + t[0] == ')' || t[0] == '\'' || + t[0] == '\\')) { + vcur--; /* back up to overwrite the \ */ + vcur[0] = t[0]; + vcur++; + t++; + esc = 0; + break; + } + + /* look at an ascii table - these ranges are the non-whitespace, non + paren and quote characters that are legal in atoms */ + if (!((t[0] >= '*' && t[0] <= '~') || + ((unsigned char)(t[0]) > 127) || + (t[0] == '!') || + (t[0] >= '#' && t[0] <= '&'))) + { + vcur[0] = '\0'; + val_used++; + + elts++; + + if (event_handlers != NULL && + event_handlers->characters != NULL) { + if (squoted != 0) + event_handlers->characters(val,val_used,SEXP_SQUOTE); + else + event_handlers->characters(val,val_used,SEXP_BASIC); + } + + vcur = val; + val_used = 0; + + if (stack->height < 1) { + /* looks like this expression was just a basic atom - so + return it. */ + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->mode = mode; + cc->error = SEXP_ERR_OK; + cc->val = val; + cc->val_used = val_used; + cc->val_allocated = val_allocated; + cc->vcur = vcur; + cc->squoted = 0; + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->last_sexp = NULL; + cc->event_handlers = event_handlers; + + return cc; + } + + switch (t[0]) { + case ' ': + case '\t': + case '\n': + case '\r': + /** NOTE: we know whitespace following atom, so spin ahead + one and let state 1 do what it needs to for the next + character. **/ + state = 1; + t++; + squoted = 0; + break; + case ')': + squoted = 0; + state = 3; + break; + default: + squoted = 0; + state = 1; + } + } + else + { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + } + break; + case 5: + if (esc == 1 && (t[0] == '\"' || + t[0] == '\'' || + t[0] == '(' || + t[0] == ')' || + t[0] == '\\')) { + vcur--; + vcur[0] = t[0]; + vcur++; + /** NO NEED TO UPDATE VAL COUNTS **/ + t++; + esc = 0; + } + + if (t[0] == '\"') + { + state = 6; + + if (squoted == 1) { + vcur[0] = '\"'; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + } + + vcur[0] = '\0'; + + val_used++; + elts++; + + if (event_handlers != NULL && + event_handlers->characters != NULL) { + if (squoted == 1) + event_handlers->characters(val,val_used,SEXP_SQUOTE); + else + event_handlers->characters(val,val_used,SEXP_DQUOTE); + } + + vcur = val; + val_used = 0; + + if (stack->height < 1) { + /* looks like this expression was just a basic double + quoted atom - so return it. */ + t++; /* spin past the quote */ + + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->mode = mode; + cc->squoted = 0; + cc->error = SEXP_ERR_OK; + cc->val = val; + cc->val_used = val_used; + cc->val_allocated = val_allocated; + cc->vcur = vcur; + cc->lastPos = t++; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->last_sexp = NULL; + cc->event_handlers = event_handlers; + + return cc; + } + } + else + { + vcur[0] = t[0]; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + if (t[0] == '\\') { + esc = 1; + } else + esc = 0; + } + + t++; + break; + case 6: + vcur = val; + state = 1; + break; + case 7: + if (t[0] == '\"') + { + state = 5; + vcur = val; + t++; + + vcur[0] = '\"'; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + squoted = 1; + } + else if (t[0] == '(') + { + vcur = val; + state = 8; + } + else + { + vcur = val; + state = 4; + squoted = 1; + } + break; + case 8: + if (esc == 0) { + if (t[0] == '(') + { + qdepth++; + } + else if (t[0] == ')') + { + qdepth--; + state = 9; + } + else if (t[0] == '\"') + { + state = 10; + } + } else { + esc = 0; + } + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + /* let it fall through to state 9 if we know we're transitioning + into that state */ + if (state != 9) + break; + case 9: + if (qdepth == 0) + { + state = 1; + vcur[0] = '\0'; + + elts++; + + if (event_handlers != NULL && + event_handlers->characters != NULL) + event_handlers->characters(val,val_used,SEXP_SQUOTE); + + vcur = val; + val_used = 0; + + if (stack->height < 1) { + /* looks like the whole expression was a single + quoted value! So return it. */ + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->mode = mode; + cc->error = SEXP_ERR_OK; + cc->squoted = 0; + cc->val = val; + cc->val_used = val_used; + cc->val_allocated = val_allocated; + cc->vcur = vcur; + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->last_sexp = NULL; + cc->event_handlers = event_handlers; + + return cc; + } + } + else + state = 8; + break; + case 10: + if (t[0] == '\"' && esc == 0) + { + state = 8; + } + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + break; + case 11: + if (t[0] == '\n') { + state = 1; + } + t++; + break; + case 12: /* pre: we saw a # and we're in inline binary mode */ + if (t[0] == 'b') { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + state = 13; /* so far, #b */ + t++; + } else { + state = 4; /* not #b, so plain ol' atom */ + } + + break; + + case 13: /* pre: we saw a #b and we're in inline binary mode */ + if (t[0] == '#') { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + state = 14; /* so far, #b# - we're definitely in binary + land now. */ + /* reset vcur to val, overwrite #b# with the size string. */ + vcur = val; + val_used = 0; + t++; + } else { + state = 4; /* not #b#, so plain ol' atom */ + } + + break; + + case 14: + /** + * so far we've read #b#. Now, the steps of the process become: + * proceed to read bytes in until we see # again. This will be + * an ASCII representation of the size. At this point, we want + * to read as many bytes as specified by this size string after + * the #. + */ + if (t[0] == '#') { /* done with size string */ + t++; + state = 15; + vcur[0] = '\0'; + + binexpected = atoi(val); + assert(binexpected > 0); + binread = 0; +#ifdef __cplusplus + bindata = (char *)sexp_malloc(sizeof(char)*binexpected); +#else + bindata = sexp_malloc(sizeof(char)*binexpected); +#endif + assert(bindata != NULL); + } else { /* still reading size string */ + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + assert(val != NULL); + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + } + + break; + + case 15: /* reading binary blob */ + bindata[binread] = t[0]; + binread++; + t++; + + if (binread == binexpected) { + /* state = 1 -- create a sexp_t and head back */ + + elts++; + + if (event_handlers != NULL && + event_handlers->binary != NULL) + event_handlers->binary(bindata, binread); + + sexp_free(bindata,binread); + bindata = NULL; + binread = binexpected = 0; + + state = 1; + + val_used = 0; + vcur = val; + + } + + break; + + default: + fprintf (stderr, "eparse_sexp: unknown parser state %d.\n", state); + break; + } + + /* the null check used to be part of the guard on the while loop. + unfortunately, if we're in state 15, null is considered a + perfectly valid byte. This means the length passed in better + be accurate for the parser to not walk off the end of the + string! */ + if (state != 15 && t[0] == '\0') keepgoing = 0; + } + + if (depth == 0 && elts > 0) { + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->mode = mode; + cc->error = SEXP_ERR_OK; + cc->val = val; + cc->squoted = squoted; + cc->val_used = val_used; + cc->val_allocated = val_allocated; + cc->vcur = vcur; + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = 1; + cc->stack = stack; + cc->esc = 0; + cc->event_handlers = event_handlers; + stack->height = 0; + cc->last_sexp = NULL; + } else { + cc->bindata = bindata; + cc->binread = binread; + cc->binexpected = binexpected; + cc->mode = mode; + cc->val = val; + cc->esc = esc; + cc->squoted = squoted; + cc->vcur = vcur; + cc->val_allocated = val_allocated; + cc->val_used = val_used; + if (t[0] == '\0' || t == bufEnd) + cc->lastPos = NULL; + else + cc->lastPos = t; + cc->depth = depth; + cc->qdepth = qdepth; + cc->state = state; + cc->stack = stack; + cc->last_sexp = NULL; + cc->event_handlers = event_handlers; + cc->error = SEXP_ERR_OK; + } + + return cc; +} diff --git a/lib/faststack.c b/lib/faststack.c new file mode 100644 index 0000000..5f00c2b --- /dev/null +++ b/lib/faststack.c @@ -0,0 +1,228 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ +/** + * faststack.c : implementation of fast stack. + * + * matt sottile / matt@lanl.gov + */ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include +#include + +/** + * create an empty stack. + */ +faststack_t * +make_stack () +{ + faststack_t *s; + +#ifdef __cplusplus + s = (faststack_t *)sexp_malloc (sizeof (faststack_t)); +#else + s = sexp_malloc (sizeof (faststack_t)); +#endif + + if (s == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + s->top = s->bottom = NULL; + s->height = 0; + + return s; +} + +/** + * free all levels of a stack + */ +void +destroy_stack (faststack_t * s) +{ + stack_lvl_t *sl; + + /* return if stack is null. no error condition - just return. */ + if (s == NULL) + return; + + /* start at the bottom */ + sl = s->bottom; + + /* if bottom is null, no levels to free. just free stack itself then. */ + if (sl == NULL) { + sexp_free(s, sizeof(faststack_t)); + return; + } + + /* go up to the top of the allocated stack */ + while (sl->above != NULL) + sl = sl->above; + + /* until we get to the bottom (where below is null), free the data + at each level and the level itself. */ + while (sl->below != NULL) + { + sl = sl->below; + sexp_free (sl->above, sizeof(stack_lvl_t)); + } + + /* free the bottom level */ + sexp_free (sl, sizeof(stack_lvl_t)); + + /* free the stack wrapper itself. */ + sexp_free (s, sizeof(faststack_t)); +} + +/** + * push a level onto the cur_stack. reuse levels that have + * been previously allocated, allocate a new one if none + * are available. + */ +faststack_t * +push (faststack_t * cur_stack, void *data) +{ + stack_lvl_t *top; + + if (cur_stack == NULL) { + sexp_errno = SEXP_ERR_BAD_STACK; + return NULL; + } + + top = cur_stack->top; + stack_lvl_t *tmp; + + /* if top isn't null, try to push above it. */ + if (top != NULL) + { + /* if above isn't null, set the stack top to it and set the + data */ + if (top->above != NULL) + { + top = cur_stack->top = cur_stack->top->above; + top->data = data; + } + else + { + /* otherwise, allocate a new level. */ + +#ifdef __cplusplus + tmp = top->above = (stack_level *)sexp_malloc (sizeof (stack_lvl_t)); +#else + tmp = top->above = sexp_malloc (sizeof (stack_lvl_t)); +#endif + + if (tmp == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + tmp->below = cur_stack->top; + tmp->above = NULL; + cur_stack->top = tmp; + tmp->data = data; + } + } + else + { + if (cur_stack->bottom != NULL) + { + cur_stack->top = cur_stack->bottom; + cur_stack->top->data = data; + } + else + { +#ifdef __cplusplus + tmp = cur_stack->top = + (stack_lvl_t *)sexp_malloc (sizeof (stack_lvl_t)); +#else + tmp = cur_stack->top = sexp_malloc (sizeof (stack_lvl_t)); +#endif + if (tmp == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + cur_stack->bottom = tmp; + tmp->above = NULL; + tmp->below = NULL; + tmp->data = data; + } + } + + cur_stack->height++; + + return cur_stack; +} + +/** + * pop the top of the stack, return the stack level that was + * popped of. + */ +stack_lvl_t * +pop (faststack_t * s) +{ + stack_lvl_t *top; + + if (s == NULL) { + sexp_errno = SEXP_ERR_BAD_STACK; + return NULL; + } + + top = s->top; + + /* if stack top isn't null, set the top pointer to the next + level down and return the old top. */ + if (top != NULL && s->height > 0) + { + s->top = s->top->below; + s->height--; + } + else + { + if (s->height < 1) return NULL; + } + + return top; +} diff --git a/lib/io.c b/lib/io.c new file mode 100644 index 0000000..7309466 --- /dev/null +++ b/lib/io.c @@ -0,0 +1,140 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * initialize an io-wrapper + */ +sexp_iowrap_t *init_iowrap(int fd) { + sexp_iowrap_t *iow; + +#ifdef __cplusplus + iow = (sexp_iowrap_t *)sexp_malloc(sizeof(sexp_iowrap_t)); +#else + iow = sexp_malloc(sizeof(sexp_iowrap_t)); +#endif + + if (iow == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + iow->cc = NULL; + iow->fd = fd; + iow->cnt = 0; + iow->buf[0] = '\0'; + + return iow; +} + +/** + * + */ +void destroy_iowrap(sexp_iowrap_t *iow) { + if (iow == NULL) return; /* idiot */ + + destroy_continuation(iow->cc); + sexp_free(iow, sizeof(sexp_iowrap_t)); +} + +/** + * + */ +sexp_t *read_one_sexp(sexp_iowrap_t *iow) { + sexp_t *sx = NULL; + + if (iow == NULL) + return NULL; + + /* check if we have more to parse from the continuation. */ + if (iow->cc != NULL && iow->cc->lastPos != NULL) { + iow->cc = cparse_sexp(iow->buf, iow->cnt, iow->cc); + + if (iow->cc == NULL) return NULL; /* cparse_sexp set sexp_errno */ + if (iow->cc->last_sexp != NULL) { + sx = iow->cc->last_sexp; + iow->cc->last_sexp = NULL; + return sx; + } + iow->cnt = 0; + } + + if (iow->cnt == 0) { + iow->cnt = read(iow->fd,iow->buf,BUFSIZ); + + if (iow->cnt == 0) { + sexp_errno = SEXP_ERR_IO_EMPTY; + return NULL; + } + } + + iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc); + + while (iow->cc->last_sexp == NULL) { + if (iow->cc->error != SEXP_ERR_OK) { + sexp_errno = iow->cc->error; + return NULL; + } + + iow->cnt = read(iow->fd,iow->buf,BUFSIZ); + + if (iow->cnt == 0) { + sexp_errno = SEXP_ERR_IO_EMPTY; + return NULL; + } + + iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc); + iow->cnt = 0; + } + + sx = iow->cc->last_sexp; + iow->cc->last_sexp = NULL; + + return sx; +} diff --git a/lib/libsexpr-1.2.pc.in b/lib/libsexpr-1.2.pc.in new file mode 100644 index 0000000..98f0382 --- /dev/null +++ b/lib/libsexpr-1.2.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +includedir=@includedir@/sexpr/liblibsexpr-1.2 + +Name: liblibsexpr +Description: Small, fast s-expression handling library used by Askele and Askele Ingria products (so called sexpr). +Version: @VERSION@ +Requires: +Libs: -L${libdir} -llibsexpr +Cflags: -I${includedir} diff --git a/lib/parser.c b/lib/parser.c new file mode 100644 index 0000000..452e279 --- /dev/null +++ b/lib/parser.c @@ -0,0 +1,1573 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include + +#include +#include + +/* + * constants related to atom buffer sizes and growth. + */ +static size_t sexp_val_start_size = 256; +static size_t sexp_val_grow_size = 64; + +/* + * Function for tuning growth parameters. + */ +sexp_errcode_t set_parser_buffer_params(size_t ss, size_t gs) { + if (ss > 0) + sexp_val_start_size = ss; + else + return SEXP_ERR_BAD_PARAM; + + if (gs > 0) + sexp_val_grow_size = gs; + else + return SEXP_ERR_BAD_PARAM; + + return SEXP_ERR_OK; +} + +/** + * this structure is pushed onto the stack so we can keep track of the + * first and last elements in a list. + * !!!!DON'T USE THESE OUTSIDE THIS FILE!!!! + */ +typedef struct parse_stack_data +{ + sexp_t *fst, *lst; +} +parse_data_t; + +/** + * parse_data_t stack - similar malloc prevention to sexp_t_cache. + */ +faststack_t *pd_cache; + +/** + * The global sexp_t_cache is a faststack implementing a cache of + * pre-alloced s-expression element entities. Odds are a user should never + * touch this. If you do, you're on your own. This is used internally by + * the parser and related code to store unused but allocated sexp_t elements. + * This should be left alone and manipulated only by the sexp_t_allocate and + * sexp_t_deallocate functions. Touching the stack is bad. + */ +faststack_t *sexp_t_cache; + +/** + * sexp_t allocation + */ +#ifdef _NO_MEMORY_MANAGEMENT_ +sexp_t * +sexp_t_allocate(void) { + sexp_t *sx = sexp_calloc(1, sizeof(sexp_t)); + if (sx == NULL) { + sexp_errno = SEXP_MEMORY; + return NULL; + } + + return(sx); +} +#else +sexp_t * +sexp_t_allocate(void) { + sexp_t *sx; + stack_lvl_t *l; + + if (sexp_t_cache == NULL) { + sexp_t_cache = make_stack(); + if (sexp_t_cache == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + +#ifdef __cplusplus + sx = (sexp_t *)sexp_malloc(sizeof(sexp_t)); +#else + sx = sexp_malloc(sizeof(sexp_t)); +#endif + if (sx == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + sx->next = sx->list = NULL; + } else { + if (empty_stack(sexp_t_cache)) { +#ifdef __cplusplus + sx = (sexp_t *)sexp_malloc(sizeof(sexp_t)); +#else + sx = sexp_malloc(sizeof(sexp_t)); +#endif + if (sx == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + sx->next = sx->list = NULL; + } else { + l = pop(sexp_t_cache); + sx = (sexp_t *)l->data; + } + } + + return sx; +} +#endif + +/** + * sexp_t de-allocation + */ +#ifdef _NO_MEMORY_MANAGEMENT_ +void +sexp_t_deallocate(sexp_t *s) { + if (s->ty == SEXP_VALUE && s->val != NULL) { + sexp_free(s->val,s->val_allocated); + } + + sexp_free(s,sizeof(sexp_t)); +} +#else +void +sexp_t_deallocate(sexp_t *s) { + if (s == NULL) return; + + if (sexp_t_cache == NULL) { + sexp_t_cache = make_stack(); + if (sexp_t_cache == NULL) { + + /**** HOW DO WE GET THE USER TO KNOW SOMETHING HAPPENED? ****/ + + sexp_errno = SEXP_ERR_MEMORY; + if (s->ty == SEXP_VALUE && s->val != NULL) { + sexp_free(s->val,s->val_allocated); + } + sexp_free(s,sizeof(sexp_t)); + return; + } + } + + s->list = s->next = NULL; + + if (s->ty == SEXP_VALUE && s->val != NULL) { + sexp_free(s->val,s->val_allocated); + } + + s->val = NULL; + + sexp_t_cache = push(sexp_t_cache, s); +} +#endif + +/** + * cleanup the sexp library. Note this is implemented HERE since we need + * to know about pd_cache, which is local to this file. + */ +#ifdef _NO_MEMORY_MANAGEMENT_ +void sexp_cleanup(void) { +} +#else +void sexp_cleanup(void) { + stack_lvl_t *l; + + if (pd_cache != NULL) { + l = pd_cache->top; + while (l != NULL) { + sexp_free(l->data,sizeof(parse_data_t)); + l = l->below; + } + destroy_stack(pd_cache); + pd_cache = NULL; + } + + if (sexp_t_cache != NULL) { + l = sexp_t_cache->top; + while (l != NULL) { + sexp_free(l->data,sizeof(sexp_t)); + l = l->below; + } + destroy_stack(sexp_t_cache); + sexp_t_cache = NULL; + } +} +#endif + +/** + * allocation + */ +parse_data_t * +pd_allocate(void) { + parse_data_t *p; + stack_lvl_t *l; + + if (pd_cache == NULL) { + pd_cache = make_stack(); + + if (pd_cache == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + +#ifdef __cplusplus + p = (parse_data_t *)sexp_malloc(sizeof(parse_data_t)); +#else + p = sexp_malloc(sizeof(parse_data_t)); +#endif + + if (p == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + } else { + if (empty_stack(pd_cache)) { +#ifdef __cplusplus + p = (parse_data_t *)sexp_malloc(sizeof(parse_data_t)); +#else + p = sexp_malloc(sizeof(parse_data_t)); +#endif + + if (p == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + } else { + l = pop(pd_cache); + p = (parse_data_t *)l->data; + } + } + + return p; +} + +/** + * de-allocation + */ +void +pd_deallocate(parse_data_t *p) { + if (pd_cache == NULL) { + pd_cache = make_stack(); + if (pd_cache == NULL) { + sexp_free(p, sizeof(parse_data_t)); + sexp_errno = SEXP_ERR_MEMORY; + return; + } + } + + pd_cache = push(pd_cache, p); +} + +/** + * Destroy a continuation by freeing all of its fields that it is responsible + * for managing, and then free the continuation itself. This includes internal + * buffers, stacks, etc.. + */ +void +destroy_continuation (pcont_t * pc) +{ + stack_lvl_t *lvl; + parse_data_t *lvl_data; + + if (pc == NULL) return; /* return if null passed in */ + + if (pc->stack != NULL) { + lvl = pc->stack->top; + + /* + * note that destroy_stack() does not free the data hanging off of the + * stack. we have to walk down the stack and do that here. + */ + + while (lvl != NULL) { + lvl_data = (parse_data_t *)lvl->data; + + /** + * Seems to have fixed bug with destroying partially parsed + * expression continuations with the short three lines below. + */ + if (lvl_data != NULL) { + lvl_data->lst = NULL; + destroy_sexp(lvl_data->fst); + lvl_data->fst = NULL; + + pd_deallocate(lvl_data); + lvl->data = lvl_data = NULL; + } + + lvl = lvl->below; + } + + /* + * stack has no data on it anymore, so we can free it. + */ + destroy_stack(pc->stack); + pc->stack = NULL; + } + + /* + * free up data used for INLINE_BINARY mode + */ + if (pc->bindata != NULL) { + sexp_free(pc->bindata,pc->binexpected); + pc->bindata = NULL; + } + + if (pc->val != NULL) { + sexp_free (pc->val,pc->val_allocated); + pc->val = NULL; + } + + sexp_free (pc,sizeof(pcont_t)); +} + +/* + * wrapper around cparse_sexp. assumes s contains a single, complete, + * null terminated s-expression. partial sexps or strings containing more + * than one will act up. + */ +sexp_t * +parse_sexp (char *s, size_t len) +{ + pcont_t *pc = NULL; + sexp_t *sx = NULL; + + if (len < 1 || s == NULL) return NULL; /* empty string - return */ + + pc = cparse_sexp (s, len, pc); + if (pc == NULL) return NULL; /* assume that cparse_sexp set sexp_errno */ + sx = pc->last_sexp; + sexp_errno = pc->error; + + destroy_continuation(pc); + + return sx; +} + +pcont_t * +init_continuation(char *str) +{ + pcont_t *cc; + /* new continuation... */ +#ifdef __cplusplus + cc = (pcont_t *)sexp_malloc(sizeof(pcont_t)); +#else + cc = sexp_malloc(sizeof(pcont_t)); +#endif + + if (cc == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + /* allocate atom buffer */ +#ifdef __cplusplus + cc->val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size); +#else + cc->val = sexp_malloc(sizeof(char)*sexp_val_start_size); +#endif + + if (cc->val == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_free(cc,sizeof(pcont_t)); + return NULL; + } + + /* by default we assume a normal parser */ + cc->mode = PARSER_NORMAL; + + cc->val_allocated = sexp_val_start_size; + cc->val_used = 0; + + cc->bindata = NULL; + cc->binread = cc->binexpected = 0; + + /* allocate stack */ + cc->esc = 0; + cc->stack = make_stack(); + + if (cc->stack == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_free(cc->val,sizeof(char)*sexp_val_start_size); + sexp_free(cc,sizeof(pcont_t)); + return NULL; + } + + cc->sbuffer = str; + cc->lastPos = NULL; + cc->state = 1; + cc->vcur = cc->val; + cc->depth = 0; + cc->qdepth = 0; + cc->squoted = 0; + cc->event_handlers = NULL; + + return cc; +} + +/** + * Iterative parser. Wrapper around parse_sexp that is slightly more + * intelligent and allows users to iteratively "pop" the expressions + * out of a string that contains a bunch of expressions. + * Useful if you have a string like "(foo bar)(goo har)(moo mar)" and + * want to get "(foo bar)", "(goo har)", and "(moo mar)" individually on + * repeated calls. + */ +sexp_t * +iparse_sexp (char *s, size_t len, pcont_t *cc) { + pcont_t *pc; + sexp_t *sx = NULL; + + /* + * error check. note that cc must be non-null, as this routine returns + * a sexp_t . If cc is null and a new one gets allocated, there is no + * way to return it. Thus this call requires cc to be allocated outside + * the routine. A null return value should cause sexp_errno to be checked. + */ + if (cc == NULL) { + sexp_errno = SEXP_ERR_BAD_PARAM; + return NULL; + } + + /* call the parser */ + pc = cparse_sexp(s,len,cc); + + if (pc == NULL) return NULL; /* assume cparse_sexp set sexp_errno */ + + if (cc->last_sexp != NULL) { + sexp_errno = cc->error; + sx = cc->last_sexp; + cc->last_sexp = NULL; + } + + return sx; +} + +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + +/* TEMPORARY -- THIS WILL GO AWAY WHEN eparse_sexp GETS ROLLED BACK INTO + * cparse_sexp */ +pcont_t *eparse_sexp (char *str, size_t len, pcont_t *lc); + +/** + * Continuation based parser - the guts of the package. + */ +pcont_t * +cparse_sexp (char *str, size_t len, pcont_t *lc) +{ + char *t = NULL; + char *s = NULL; + register size_t binexpected = 0; + register size_t binread = 0; + register parsermode_t mode = PARSER_NORMAL; + register size_t val_allocated = 0; + register unsigned int squoted = 0; + register size_t val_used = 0; + register unsigned int state = 1; + register unsigned int depth = 0; + register unsigned int qdepth = 0; + register unsigned int elts = 0; + register unsigned int esc = 0; + pcont_t *cc = NULL; + char *val = NULL; + char *vcur = NULL; + char *bindata = NULL; + sexp_t *sx = NULL; + faststack_t *stack = NULL; + parse_data_t *data = NULL; + stack_lvl_t *lvl = NULL; + char *bufEnd = NULL; + int keepgoing = 1; + parser_event_handlers_t *event_handlers = NULL; + + /*** define a macro used for stashing continuation state away ***/ + /** NOTE: sbuffer is set manually as appropriate. **/ +#define SAVE_CONT_STATE(err,ls) { \ + cc->bindata = bindata; \ + cc->binread = binread; \ + cc->binexpected = binexpected; \ + cc->val = val; \ + cc->mode = mode; \ + cc->squoted = squoted; \ + cc->val_used = val_used; \ + cc->val_allocated = val_allocated; \ + cc->vcur = vcur; \ + cc->lastPos = t; \ + cc->depth = depth; \ + cc->qdepth = qdepth; \ + cc->state = state; \ + cc->stack = stack; \ + cc->esc = esc; \ + cc->last_sexp = (ls); \ + cc->error = (err); \ + cc->event_handlers = event_handlers; \ +} + /*** end continuation state saving macro ***/ + + /* make sure non-null string */ + if (str == NULL) { + cc = lc; + + if (cc == NULL) { + cc = init_continuation(str); + if (cc == NULL) return NULL; /* sexp_errno was set in call */ + } + cc->error = SEXP_ERR_NULLSTRING; + cc->last_sexp = NULL; + + return cc; + } + + /* first, if we have a non null continuation passed in, restore state. */ + if (lc != NULL) { + /* if the parser mode is events only, call the parser that doesn't + allocate any elements or stack parts */ + if (lc->mode == PARSER_EVENTS_ONLY) + return eparse_sexp(str,len,lc); + + cc = lc; + binexpected = cc->binexpected; + binread = cc->binread; + bindata = cc->bindata; + val_used = cc->val_used; + val_allocated = cc->val_allocated; + squoted = cc->squoted; + val = cc->val; + vcur = cc->vcur; + state = cc->state; + depth = cc->depth; + qdepth = cc->qdepth; + stack = cc->stack; + esc = cc->esc; + mode = cc->mode; + event_handlers = cc->event_handlers; + s = str; + if (cc->lastPos != NULL) + t = cc->lastPos; + else { + t = s; + cc->sbuffer = str; + } + } else { + /* new continuation... */ + cc = init_continuation(str); + if (cc == NULL) return NULL; + + /* explicitly set mode -- init continuation defaults to PARSER_NORMAL */ + cc->mode = mode; + val = cc->val; + + val_used = cc->val_used; + val_allocated = cc->val_allocated; + + vcur = val; + + /* allocate stack */ + stack = cc->stack; + + /* t is temp pointer into s for current position */ + s = str; + t = s; + } + + bufEnd = cc->sbuffer+len; + + /* guard for loop - see end of loop for info. Put it out here in the + event that we're restoring state from a continuation and need to + check before we start up. */ + if (state != 15 && t[0] == '\0') keepgoing = 0; + + /*==================*/ + /* main parser loop */ + /*==================*/ + while (keepgoing == 1 && t != bufEnd) + { + /* based on the current state in the FSM, do something */ + switch (state) + { + case 1: + switch (t[0]) + { + /* space,tab,CR,LF considered white space */ + case '\n': + case ' ': + case '\t': + case '\r': + t++; + break; + /* semicolon starts a comment that extends until a \n is + encountered. */ + case ';': + t++; + state = 11; + break; + /* enter state 2 for open paren */ + case '(': + state = 2; + t++; + if (event_handlers != NULL && + event_handlers->start_sexpr != NULL) + event_handlers->start_sexpr(); + break; + /* enter state 3 for close paren */ + case ')': + state = 3; + break; + /* begin quoted string - enter state 5 */ + case '\"': + state = 5; + /* set cur pointer to beginning of val buffer */ + vcur = val; + t++; + break; + /* single quote - enter state 7 */ + case '\'': + state = 7; + t++; + break; + /* other characters are assumed to be atom parts */ + default: + /* set cur pointer to beginning of val buffer */ + vcur = val; + + /** NOTE: the following code originally required a transition + to state 4 before processing the first atom character -- + this required two iterations for the first character + of each atom. merging this into here allows us to process + what we already know to be a valid atom character before + entering state 4. **/ + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { +#ifdef __cplusplus + val = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + val = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (val == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY,NULL); + return cc; + } + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + /* if the atom starts with # and we're in inline + binary mode, we need to go to state 12 to start + checking for the #b# prefix. otherwise, + if it's not a # or we're just in normal mode, + proceed to state 4 as usual. */ + if (t[0] == '#' && mode == PARSER_INLINE_BINARY) { + state = 12; + } else { + state = 4; + } + + t++; + break; + } + break; + case 2: + /* open paren */ + depth++; + + sx = sexp_t_allocate(); + + if (sx == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY,NULL); + return cc; + } + + elts++; + sx->ty = SEXP_LIST; + sx->next = NULL; + sx->list = NULL; + + if (stack->height < 1) + { + data = pd_allocate(); + + if (data == NULL) { + sexp_t_deallocate(sx); + SAVE_CONT_STATE(SEXP_ERR_MEMORY,NULL); + return cc; + } + + data->fst = data->lst = sx; + push (stack, data); + } + else + { + data = (parse_data_t *) top_data (stack); + if (data->lst != NULL) + data->lst->next = sx; + else + data->fst = sx; + data->lst = sx; + } + + data = pd_allocate(); + if (data == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY,NULL); + return cc; + } + data->fst = data->lst = NULL; + push (stack, data); + + state = 1; + break; + case 3: + /** close paren **/ + + /* check for close parens that were never opened. */ + if (depth == 0) { + esc = 0; + state = 1; + SAVE_CONT_STATE(SEXP_ERR_BADFORM,NULL); + return cc; + } + + t++; + depth--; + + lvl = pop (stack); + data = (parse_data_t *) lvl->data; + sx = data->fst; + pd_deallocate(data); + lvl->data = NULL; + + if (stack->top != NULL) + { + data = (parse_data_t *) top_data (stack); + data->lst->list = sx; + } + else + { + SAVE_CONT_STATE(SEXP_ERR_BAD_STACK, NULL); + return cc; + } + + if (event_handlers != NULL && + event_handlers->end_sexpr != NULL) + event_handlers->end_sexpr(); + + state = 1; + + /** if depth = 0 then we finished a sexpr, and we return **/ + if (depth == 0) { + while (stack->top != NULL) + { + lvl = pop (stack); + data = (parse_data_t *) lvl->data; + sx = data->fst; + pd_deallocate(data); + lvl->data = NULL; + } + + esc = 0; + state = 1; + SAVE_CONT_STATE(SEXP_ERR_OK, sx); + + return cc; + } + break; + case 4: /** parsing atom **/ + if (esc == 1 && (t[0] == '\"' || t[0] == '(' || + t[0] == ')' || t[0] == '\'' || + t[0] == '\\')) { + vcur--; /* back up to overwrite the \ */ + vcur[0] = t[0]; + vcur++; + t++; + esc = 0; + break; + } + + /* look at an ascii table - these ranges are the non-whitespace, non + paren and quote characters that are legal in atoms */ + if (!((t[0] >= '*' && t[0] <= '~') || + ((unsigned char)(t[0]) > 127) || + (t[0] == '!') || + (t[0] >= '#' && t[0] <= '&'))) + { + vcur[0] = '\0'; + val_used++; + + sx = sexp_t_allocate(); + + if (sx == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + elts++; + sx->ty = SEXP_VALUE; + sx->val = val; + sx->val_allocated = val_allocated; + sx->val_used = val_used; + sx->next = NULL; + if (squoted != 0) + sx->aty = SEXP_SQUOTE; + else + sx->aty = SEXP_BASIC; + + if (event_handlers != NULL && + event_handlers->characters != NULL) + event_handlers->characters(sx->val,sx->val_used,sx->aty); + +#ifdef __cplusplus + val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size); +#else + val = sexp_malloc(sizeof(char)*sexp_val_start_size); +#endif + + if (val == NULL) { + sexp_t_deallocate(sx); + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val_allocated = sexp_val_start_size; + val_used = 0; + vcur = val; + + if (!empty_stack (stack)) + { + data = (parse_data_t *) top_data (stack); + if (data->fst == NULL) + { + data->fst = data->lst = sx; + } + else + { + data->lst->next = sx; + data->lst = sx; + } + } + else + { + /* looks like this expression was just a basic atom - so + return it. */ + squoted = 0; + state = 1; + esc = 0; + SAVE_CONT_STATE(SEXP_ERR_OK, sx); + return cc; + } + + switch (t[0]) { + case ' ': + case '\t': + case '\n': + case '\r': + /** NOTE: we know whitespace following atom, so spin ahead + one and let state 1 do what it needs to for the next + character. **/ + state = 1; + t++; + squoted = 0; + break; + case ')': + squoted = 0; + state = 3; + break; + default: + squoted = 0; + state = 1; + } + } + else + { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + } + break; + case 5: + if (esc == 1 && (t[0] == '\"' || + t[0] == '\'' || + t[0] == '(' || + t[0] == ')' || + t[0] == '\\')) { + vcur--; + vcur[0] = t[0]; + vcur++; + /** NO NEED TO UPDATE VAL COUNTS **/ + t++; + esc = 0; + } + + if (t[0] == '\"') + { + state = 6; + + if (squoted == 1) { + vcur[0] = '\"'; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+ + sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + } + + vcur[0] = '\0'; + + val_used++; + sx = sexp_t_allocate(); + + if (sx == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + elts++; + sx->ty = SEXP_VALUE; + sx->val = val; + sx->val_used = val_used; + sx->val_allocated = val_allocated; + sx->next = NULL; + + if (squoted == 1) { + sx->aty = SEXP_SQUOTE; + squoted = 0; + } else + sx->aty = SEXP_DQUOTE; + + if (event_handlers != NULL && + event_handlers->characters != NULL) + event_handlers->characters(sx->val,sx->val_used,sx->aty); + +#ifdef __cplusplus + val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size); +#else + val = sexp_malloc(sizeof(char)*sexp_val_start_size); +#endif + + if (val == NULL) { + sexp_t_deallocate(sx); + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val_allocated = sexp_val_start_size; + val_used = 0; + vcur = val; + + if (!empty_stack (stack)) + { + data = (parse_data_t *) top_data (stack); + if (data->fst == NULL) + { + data->fst = data->lst = sx; + } + else + { + data->lst->next = sx; + data->lst = sx; + } + } + else + { + /* looks like this expression was just a basic double + quoted atom - so return it. */ + t++; /* spin past the quote */ + + squoted = 0; + esc = 0; + state = 1; + SAVE_CONT_STATE(SEXP_ERR_OK, sx); + + return cc; + } + } + else + { + vcur[0] = t[0]; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + if (t[0] == '\\') { + esc = 1; + } else + esc = 0; + } + + t++; + break; + case 6: + vcur = val; + state = 1; + break; + case 7: + if (t[0] == '\"') + { + state = 5; + vcur = val; + t++; + + vcur[0] = '\"'; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + squoted = 1; + } + else if (t[0] == '(') + { + vcur = val; + state = 8; + } + else + { + vcur = val; + state = 4; + squoted = 1; + } + break; + case 8: + if (esc == 0) { + if (t[0] == '(') + { + qdepth++; + } + else if (t[0] == ')') + { + qdepth--; + state = 9; + } + else if (t[0] == '\"') + { + state = 10; + } + } else { + esc = 0; + } + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + /* let it fall through to state 9 if we know we're transitioning + into that state */ + if (state != 9) + break; + case 9: + if (qdepth == 0) + { + state = 1; + vcur[0] = '\0'; + sx = sexp_t_allocate(); + + if (sx == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + elts++; + sx->ty = SEXP_VALUE; + sx->val = val; + sx->val_allocated = val_allocated; + sx->val_used = val_used; + sx->next = NULL; + sx->aty = SEXP_SQUOTE; + + if (event_handlers != NULL && + event_handlers->characters != NULL) + event_handlers->characters(sx->val,sx->val_used,sx->aty); + +#ifdef __cplusplus + val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size); +#else + val = sexp_malloc(sizeof(char)*sexp_val_start_size); +#endif + + if (val == NULL) { + sexp_t_deallocate(sx); + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val_allocated = sexp_val_start_size; + val_used = 0; + vcur = val; + + if (!empty_stack (stack)) + { + data = (parse_data_t *) top_data (stack); + if (data->fst == NULL) + { + data->fst = data->lst = sx; + } + else + { + data->lst->next = sx; + data->lst = sx; + } + } + else + { + /* looks like the whole expression was a single + quoted value! So return it. */ + squoted = 0; + esc = 0; + state = 1; + SAVE_CONT_STATE(SEXP_ERR_OK, sx); + return cc; + } + } + else + state = 8; + break; + case 10: + if (t[0] == '\"' && esc == 0) + { + state = 8; + } + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + break; + case 11: + if (t[0] == '\n') { + state = 1; + } + t++; + break; + case 12: /* pre: we saw a # and we're in inline binary mode */ + if (t[0] == 'b') { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + state = 13; /* so far, #b */ + t++; + } else { + state = 4; /* not #b, so plain ol' atom */ + } + + break; + + case 13: /* pre: we saw a #b and we're in inline binary mode */ + if (t[0] == '#') { + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + state = 14; /* so far, #b# - we're definitely in binary + land now. */ + /* reset vcur to val, overwrite #b# with the size string. */ + vcur = val; + val_used = 0; + t++; + } else { + state = 4; /* not #b#, so plain ol' atom */ + } + + break; + + case 14: + /** + * so far we've read #b#. Now, the steps of the process become: + * proceed to read bytes in until we see # again. This will be + * an ASCII representation of the size. At this point, we want + * to read as many bytes as specified by this size string after + * the #. + */ + if (t[0] == '#') { /* done with size string */ + t++; + state = 15; + vcur[0] = '\0'; + + binexpected = atoi(val); + + if (binexpected < 0) { + SAVE_CONT_STATE(SEXP_ERR_BADCONTENT, NULL); + return cc; + } + + binread = 0; + if (binexpected > 0) { +#ifdef __cplusplus + bindata = (char *)sexp_malloc(sizeof(char)*binexpected); +#else + bindata = sexp_malloc(sizeof(char)*binexpected); +#endif + + if (bindata == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + } else { + bindata = NULL; + } + } else { /* still reading size string */ + vcur[0] = t[0]; + if (t[0] == '\\') esc = 1; + else esc = 0; + val_used++; + + if (val_used == val_allocated) { + char *valnew = NULL; + +#ifdef __cplusplus + valnew = (char *)sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#else + valnew = sexp_realloc(val, + val_allocated+sexp_val_grow_size, + val_allocated); +#endif + + if (valnew == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + val = valnew; + + vcur = val + val_used; + val_allocated += sexp_val_grow_size; + } else vcur++; + + t++; + } + + break; + + case 15: /* reading binary blob */ + if (binread < binexpected) { + bindata[binread] = t[0]; + binread++; + t++; + } + + if (binread == binexpected) { + /* state = 1 -- create a sexp_t and head back */ + sx = sexp_t_allocate(); + + if (sx == NULL) { + SAVE_CONT_STATE(SEXP_ERR_MEMORY, NULL); + return cc; + } + + elts++; + sx->ty = SEXP_VALUE; + sx->bindata = bindata; + sx->binlength = binread; + sx->next = NULL; + sx->aty = SEXP_BINARY; + + if (event_handlers != NULL && + event_handlers->binary != NULL) + event_handlers->binary(sx->bindata, sx->binlength); + + bindata = NULL; + binread = binexpected = 0; + + state = 1; + + val_used = 0; + vcur = val; + + if (!empty_stack (stack)) + { + data = (parse_data_t *) top_data (stack); + if (data->fst == NULL) + { + data->fst = data->lst = sx; + } + else + { + data->lst->next = sx; + data->lst = sx; + } + } + + } + + break; + + default: + SAVE_CONT_STATE(SEXP_ERR_UNKNOWN_STATE, NULL); + return cc; + } + + /* the null check used to be part of the guard on the while loop. + unfortunately, if we're in state 15, null is considered a + perfectly valid byte. This means the length passed in better + be accurate for the parser to not walk off the end of the + string! */ + if (state != 15 && t[0] == '\0') keepgoing = 0; + } + + if (depth == 0 && elts > 0) { + while (stack->top != NULL) + { + lvl = pop (stack); + data = (parse_data_t *) lvl->data; + sx = data->fst; + pd_deallocate(data); + lvl->data = NULL; + } + + esc = 0; + state = 1; + SAVE_CONT_STATE(SEXP_ERR_OK, sx); + } else { + SAVE_CONT_STATE(SEXP_ERR_OK, NULL); + if (t[0] == '\0' || t == bufEnd) + cc->lastPos = NULL; + else + cc->lastPos = t; + } + + return cc; +} diff --git a/lib/sexp.c b/lib/sexp.c new file mode 100644 index 0000000..52d7c2c --- /dev/null +++ b/lib/sexp.c @@ -0,0 +1,546 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include + +#include +#include + +/* + * global error code that can be set by sexp library calls. default + * is SEXP_ERR_OK. + */ +sexp_errcode_t sexp_errno = SEXP_ERR_OK; + +void reset_sexp_errno() { + sexp_errno = SEXP_ERR_OK; +} + +/** + * Recursively walk an s-expression and free it. + */ +void +destroy_sexp (sexp_t * s) +{ + if (s == NULL) + return; + + if (s->ty == SEXP_LIST) { + destroy_sexp (s->list); + } else if (s->ty == SEXP_VALUE) { + if (s->aty == SEXP_BINARY && s->bindata != NULL) { + sexp_free(s->bindata, s->binlength); + } else if (s->val != NULL) { + sexp_free(s->val, s->val_allocated); + } + } + + s->val = NULL; + s->bindata = NULL; + + destroy_sexp (s->next); + + s->next = s->list = NULL; + + sexp_t_deallocate(s); +} + +/** + * Iterative method to walk sx and turn it back into the string + * representation of the s-expression. Fills the buffer. + */ +int +print_sexp (char *buf, size_t size, const sexp_t * sx) +{ + int retval; + int sz; + char *b = buf, *tc; + size_t left = size; + int depth = 0; + faststack_t *stack; + stack_lvl_t *top; + sexp_t *tdata; + sexp_t *fakehead; + sexp_t tmp; + + if (sx == NULL) { + buf[0] = '\0'; + return 0; + } + + tmp = *sx; + tmp.next = tmp.list = NULL; + + fakehead = copy_sexp(&tmp); + + if (fakehead == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return -1; + } + + fakehead->list = sx->list; + fakehead->next = NULL; /* this is the important part of fakehead */ + + stack = make_stack (); + if (stack == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_t_deallocate(fakehead); + return -1; + } + + push (stack, fakehead); + + while (stack->top != NULL) + { + top = stack->top; + tdata = (sexp_t *) top->data; + + if (tdata == NULL) + { + pop (stack); + + if (depth > 0) + { + b[0] = ')'; + b++; + left--; + depth--; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + } + + if (stack->top == NULL) + break; + + top = stack->top; + top->data = ((sexp_t *) top->data)->next; + if (top->data != NULL) + { + b[0] = ' '; + b++; + left--; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + } + } + else if (tdata->ty == SEXP_VALUE) + { + if (tdata->aty == SEXP_DQUOTE) + { + b[0] = '\"'; + b++; + left--; + } + else if (tdata->aty == SEXP_SQUOTE) + { + b[0] = '\''; + b++; + left--; + } + + if (tdata->aty != SEXP_BINARY && tdata->val_used > 0) { + tc = tdata->val; + /* copy value into string */ + while (tc[0] != 0 && left > 0) + { + /* escape characters that need escaping. */ + if ((tc[0] == '\"' || tc[0] == '\\') && + tdata->aty == SEXP_DQUOTE) + { + b[0] = '\\'; + b++; + left--; + if (left == 0) break; + } + + b[0] = tc[0]; + b++; + tc++; + left--; + if (left == 0) + break; + } + } else { + if (left > 3) { + b[0] = '#'; b[1] = 'b'; b[2] = '#'; + b+=3; + left-=3; + +#ifndef WIN32 + if ((size_t)(sz = snprintf(b,left,"%lu#",(unsigned long)tdata->binlength)) >= left) { +#else + if ((sz = _snprintf(b,left,"%lu#",tdata->binlength)) >= left) { +#endif + left = 0; + break; + } + b += sz; + left -= sz; + + if (left < tdata->binlength) { + left = 0; + break; + } + + if (tdata->binlength > 0) { + memcpy(b,tdata->bindata,tdata->binlength); + left -= tdata->binlength; + b+=tdata->binlength; + } + + b[0] = ' '; + left--; + + } else { + left = 0; + break; + } + } + + if (tdata->aty == SEXP_DQUOTE && left > 0) + { + b[0] = '\"'; + b++; + left--; + } + + if (left < 0) + left = 0; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + + top->data = ((sexp_t *) top->data)->next; + + if (top->data != NULL) + { + b[0] = ' '; + b++; + left--; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + } + } + else if (tdata->ty == SEXP_LIST) + { + depth++; + b[0] = '('; + b++; + left--; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + + push (stack, tdata->list); + } + else + { + sexp_errno = SEXP_ERR_BADCONTENT; + destroy_stack (stack); + sexp_t_deallocate(fakehead); + return -1; + } + + } + while (depth != 0) + { + b[0] = ')'; + b++; + left--; + depth--; + if (left == 0) + { + sexp_errno = SEXP_ERR_BUFFER_FULL; + break; + } + } + + if (left != 0) { + b[0] = 0; + retval = (size-left); + } else { + b--; + b[0] = 0; + retval = -1; + } + + destroy_stack (stack); + sexp_t_deallocate(fakehead); + + return retval; +} + +/** + * Iterative method to walk sx and turn it back into the string + * representation of the s-expression. Fills the CSTRING that is + * passed in. If *s == NULL (new CSTRING, never used), snew() is called + * and passed back. If *s != NULL, *s is used as the CSTRING to print + * into. In the last case, the recycled CSTRING must have sempty() called + * to reset the allocated vs. used counters to make it appear to be empty. + * the code will assume that sempty() was called by the user! + */ +int +print_sexp_cstr (CSTRING **s, const sexp_t *sx, size_t ss) +{ + int retval; + char *tc; + int depth = 0; + faststack_t *stack; + stack_lvl_t *top; + sexp_t *tdata; + sexp_t *fakehead; + CSTRING *_s = NULL; + char sbuf[32]; + unsigned int i; + sexp_t tmp; + + if (sx == NULL) { + return -1; + } + + if (*s == NULL) + _s = snew(ss); + else + _s = *s; + + tmp = *sx; + tmp.next = tmp.list = NULL; + + fakehead = copy_sexp(&tmp); + + if (fakehead == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return -1; + } + + fakehead->list = sx->list; + fakehead->next = NULL; /* this is the important part of fakehead */ + + stack = make_stack (); + if (stack == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_t_deallocate(fakehead); + return -1; + } + + push (stack, fakehead); + + while (stack->top != NULL) + { + top = stack->top; + tdata = (sexp_t *) top->data; + + if (tdata == NULL) + { + pop (stack); + + if (depth > 0) + { + _s = saddch(_s, ')'); + depth--; + } + + if (stack->top == NULL) + break; + + top = stack->top; + top->data = ((sexp_t *) top->data)->next; + if (top->data != NULL) + { + _s = saddch(_s, ' '); + } + } + else if (tdata->ty == SEXP_VALUE) + { + if (tdata->aty == SEXP_DQUOTE) + { + _s = saddch(_s,'\"'); + } + else if (tdata->aty == SEXP_SQUOTE) + { + _s = saddch(_s,'\''); + } + + if (tdata->aty == SEXP_BINARY) { + sprintf(sbuf,"#b#%lu#",(unsigned long)tdata->binlength); + + _s = sadd(_s,sbuf); + + for (i=0;ibinlength;i++) + _s = saddch(_s,tdata->bindata[i]); + _s = saddch(_s,' '); + } else { + if (tdata->val_used > 0) { + tc = tdata->val; + + /* copy value into string */ + while (tc[0] != 0) + { + /* escape characters that need escaping. */ + if ((tc[0] == '\"' || + tc[0] == '\\') && tdata->aty == SEXP_DQUOTE) + { + _s = saddch(_s,'\\'); + } + + _s = saddch(_s,tc[0]); + tc++; + } + } + } + + if (tdata->aty == SEXP_DQUOTE) + { + _s = saddch(_s,'\"'); + } + + top->data = ((sexp_t *) top->data)->next; + + if (top->data != NULL) + { + _s = saddch(_s,' '); + } + } + else if (tdata->ty == SEXP_LIST) + { + depth++; + _s = saddch(_s,'('); + push (stack, tdata->list); + } + else + { + sexp_errno = SEXP_ERR_BADCONTENT; + destroy_stack (stack); + sexp_t_deallocate(fakehead); + return -1; + } + + } + while (depth != 0) + { + _s = saddch(_s,')'); + depth--; + } + + *s = _s; + if (_s == NULL) + retval = 0; + else + retval = _s->curlen; + + destroy_stack (stack); + sexp_t_deallocate(fakehead); + + return retval; +} + +/** + * Allocate a new sexp_t element representing a list. + */ +sexp_t *new_sexp_list(sexp_t *l) { + sexp_t *sx = sexp_t_allocate(); + + if (sx == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + sx->ty = SEXP_LIST; + + sx->list = l; + sx->next = NULL; + + sx->val = NULL; + sx->val_used = sx->val_allocated = 0; + + return sx; +} + +/** + * allocate a new sexp_t element representing a value + */ +sexp_t *new_sexp_atom(const char *buf, size_t bs, atom_t aty) { + sexp_t *sx = sexp_t_allocate(); + + if (sx == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + sx->ty = SEXP_VALUE; + sx->aty = aty; + +#ifdef __cplusplus + sx->val = (char *)sexp_malloc(sizeof(char)*(bs+1)); +#else + sx->val = sexp_malloc(sizeof(char)*(bs+1)); +#endif + + if (sx->val == NULL) { + sexp_t_deallocate(sx); + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + sx->val_used = sx->val_allocated = bs+1; + + strcpy(sx->val,buf); + + sx->list = sx->next = NULL; + + return sx; +} diff --git a/lib/sexp_memory.c b/lib/sexp_memory.c new file mode 100644 index 0000000..c297ac1 --- /dev/null +++ b/lib/sexp_memory.c @@ -0,0 +1,132 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include + +#include +#include +#include + +#ifdef _SEXP_LIMIT_MEMORY_ + +static size_t sexp_max_memory = 32*1024*1024; /* default: 32MB */ +static size_t sexp_used_memory = 0; + +size_t get_sexp_max_memory() { + return sexp_max_memory; +} + +size_t get_sexp_used_memory() { + return sexp_used_memory; +} + +int set_sexp_max_memory(size_t newsize) { + if (newsize > 0) { + if (newsize < sexp_used_memory) { + sexp_errno = SEXP_ERR_BAD_PARAM; + return -1; + } else { + sexp_max_memory = newsize; + } + } else { + sexp_errno = SEXP_ERR_BAD_PARAM; + return -1; + } + + return sexp_max_memory; +} + +void *sexp_malloc(size_t size) { + void *ptr; + + if (sexp_used_memory+size > sexp_max_memory) { + sexp_errno = SEXP_ERR_MEM_LIMIT; + return NULL; + } + + ptr = malloc(size); + if (ptr != NULL) sexp_used_memory += size; + + return ptr; +} + +void *sexp_calloc(size_t count, size_t size) { + void *ptr; + + if (sexp_used_memory+(size*count) > sexp_max_memory) { + sexp_errno = SEXP_ERR_MEM_LIMIT; + return NULL; + } + + ptr = calloc(count, size); + if (ptr != NULL) sexp_used_memory += size*count; + + return ptr; +} + + +void sexp_free(void *ptr, size_t size) { + if (sexp_used_memory < size) { + fprintf(stderr,"ERROR: sexp_free called too many times!\n"); + } else { + sexp_used_memory -= size; + } + + free(ptr); +} + +void *sexp_realloc(void *ptr, size_t size, size_t oldsize) { + void *p; + + if (sexp_used_memory+(size-oldsize) > sexp_max_memory) { + sexp_errno = SEXP_ERR_MEM_LIMIT; + return NULL; + } + + p = realloc(ptr,size); + if (p != NULL) sexp_used_memory += size-oldsize; + + return p; +} + +#endif /* _SEXP_LIMIT_MEMORY_ */ diff --git a/lib/sexp_ops.c b/lib/sexp_ops.c new file mode 100644 index 0000000..57e4548 --- /dev/null +++ b/lib/sexp_ops.c @@ -0,0 +1,230 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include +#include + +#include + +/** + * Given an s-expression, find the atom inside of it with the + * value matchine name, and return a reference to it. If the atom + * doesn't occur inside start, return NULL. + */ +sexp_t * +find_sexp (const char *name, sexp_t * start) +{ + sexp_t *temp; + + if (start == NULL) + return NULL; + + if (start->ty == SEXP_LIST) + { + temp = find_sexp (name, start->list); + if (temp == NULL) + return find_sexp (name, start->next); + else + return temp; + } + else + { + if (start->val != NULL && strcmp (start->val, name) == 0) + return start; + else + return find_sexp (name, start->next); + } + + return NULL; /* shouldn't get here */ +} + +/** + * Breadth first search - look at ->next before ->list when seeing list + * elements of an expression. + */ +sexp_t *bfs_find_sexp(const char *str, sexp_t *sx) { + sexp_t *t = sx; + sexp_t *rt; + + if (sx == NULL) return NULL; + + while (t != NULL) { + if (t->ty == SEXP_VALUE) { + if (t->val != NULL) { + if (strcmp(t->val,str) == 0) { + return t; + } + } + } + + t = t->next; + } + + t = sx; + while (t != NULL) { + if (t->ty == SEXP_LIST) { + rt = bfs_find_sexp(str,t->list); + if (rt != NULL) return rt; + } + + t = t->next; + } + + return NULL; +} + +/** + * Give the length of a s-expression list. + */ +int sexp_list_length(const sexp_t *sx) { + int len = 0; + const sexp_t *t; + + if (sx == NULL) return 0; + + if (sx->ty == SEXP_VALUE) return 1; + + t = sx->list; + + while (t != NULL) { + len++; + t = t->next; + } + return len; +} + +/** + * Copy an s-expression. + */ +sexp_t *copy_sexp(const sexp_t *s) { + sexp_t *snew; + + if (s == NULL) return NULL; + + snew = sexp_t_allocate(); + if (snew == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + return NULL; + } + + /* initialize fields to null and zero, and fill in only those necessary. */ + snew->val_allocated = snew->val_used = 0; + snew->val = NULL; + snew->list = snew->next = NULL; + snew->bindata = NULL; + snew->binlength = 0; + + /* now start copying in data and setting appropriate fields. */ + snew->ty = s->ty; + + /* values */ + if (snew->ty == SEXP_VALUE) { + snew->aty = s->aty; + + /* binary */ + if (snew->aty == SEXP_BINARY) { + if (s->bindata == NULL && s->binlength > 0) { + sexp_errno = SEXP_ERR_BADCONTENT; + sexp_t_deallocate(snew); + return NULL; + } + + snew->binlength = s->binlength; + + if (s->bindata == NULL) { + snew->bindata = NULL; + } else { + /** allocate space **/ +#ifdef __cplusplus + snew->bindata = (char *)sexp_malloc(sizeof(char)*s->binlength); +#else + snew->bindata = sexp_malloc(sizeof(char)*s->binlength); +#endif + } + + if (snew->bindata == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_t_deallocate(snew); + return NULL; + } + + memcpy(snew->bindata,s->bindata,s->binlength*sizeof(char)); + + /* non-binary */ + } else { + if (s->val == NULL && (s->val_used > 0 || s->val_allocated > 0)) { + sexp_errno = SEXP_ERR_BADCONTENT; + sexp_t_deallocate(snew); + return NULL; + } + + snew->val_used = snew->val_allocated = s->val_used; + + if (s->val == NULL) { + snew->val = NULL; + } else { + /** allocate space **/ +#ifdef __cplusplus + snew->val = (char *)sexp_malloc(sizeof(char)*s->val_used); +#else + snew->val = sexp_malloc(sizeof(char)*s->val_used); +#endif + + if (snew->val == NULL) { + sexp_errno = SEXP_ERR_MEMORY; + sexp_t_deallocate(snew); + return NULL; + } + + strcpy(snew->val,s->val); + } + } + } else { + snew->list = copy_sexp(s->list); + } + + snew->next = copy_sexp(s->next); + + return snew; +} + diff --git a/lib/sexp_vis.c b/lib/sexp_vis.c new file mode 100644 index 0000000..1408f80 --- /dev/null +++ b/lib/sexp_vis.c @@ -0,0 +1,130 @@ +/** +@cond IGNORE + +====================================================== + SFSEXP: Small, Fast S-Expression Library version 1.2 + Written by Matthew Sottile (matt@cs.uoregon.edu) +====================================================== + +Copyright (2003-2006). The Regents of the University of California. This +material was produced under U.S. Government contract W-7405-ENG-36 for Los +Alamos National Laboratory, which is operated by the University of +California for the U.S. Department of Energy. The U.S. Government has rights +to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR +THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY +LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce +derivative works, such modified software should be clearly marked, so as not +to confuse it with the version available from LANL. + +Additionally, this library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA + +LA-CC-04-094 + +@endcond +**/ + +/** + * Ported to Jari OS by Alfeiks Kaanoken + * (c) Jari OS Core dev team 2005-2009 + */ + +#include +#include + +void _sexp_to_dotfile(const sexp_t *sx, FILE *fp) { + const sexp_t *tmp; + + tmp = sx; + + while (tmp != NULL) { + fprintf(fp," sx%lu [shape=record,label=\"",(unsigned long)tmp); + if (tmp->ty == SEXP_VALUE) { + fprintf(fp,"{ SEXP_VALUE | "); + switch (tmp->aty) { + case SEXP_BASIC: + fprintf(fp,"SEXP_BASIC }"); + break; + case SEXP_SQUOTE: + fprintf(fp,"SEXP_SQUOTE }"); + break; + case SEXP_DQUOTE: + fprintf(fp,"SEXP_DQUOTE }"); + break; + case SEXP_BINARY: + fprintf(fp,"SEXP_BINARY }"); + break; + default: + fprintf(fp,"ATY Unknown }"); + break; + } + } else + fprintf(fp," SEXP_LIST"); + + if (tmp->ty == SEXP_LIST) { + fprintf(fp,"| list | next\"];\n"); + + if (tmp->list != NULL) { + fprintf(fp," sx%lu:list -> sx%lu:type;\n", + (unsigned long)tmp, + (unsigned long)tmp->list); + _sexp_to_dotfile(tmp->list,fp); + if (tmp->next != NULL) + fprintf(fp," sx%lu:next -> sx%lu:type;\n", + (unsigned long)tmp, + (unsigned long)tmp->next); + tmp = tmp->next; + } + } else { + if (tmp->aty == SEXP_BINARY) + fprintf(fp,"| binlength=%lu | next\"];\n", + (unsigned long)tmp->binlength); + else + fprintf(fp,"| { va=%lu | vu=%lu } | val=%s | next\"];\n", + (unsigned long)tmp->val_allocated, + (unsigned long)tmp->val_used, + tmp->val); + + if (tmp->next != NULL) + fprintf(fp," sx%lu:next -> sx%lu:type;\n", + (unsigned long)tmp, + (unsigned long)tmp->next); + tmp = tmp->next; + + } + } +} + +sexp_errcode_t sexp_to_dotfile(const sexp_t *sx, const char *fname) { + FILE *fp; + + if (sx == NULL || fname == NULL) { + return SEXP_ERR_NULLSTRING; + } + + fp = fopen(fname,"w+"); + if (fp == NULL) { + return SEXP_ERR_IO; + } + + fprintf(fp,"digraph sexp {\n"); + + _sexp_to_dotfile(sx,fp); + + fprintf(fp,"}\n"); + + fclose(fp); + + return SEXP_ERR_OK; +} diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..bc8cbb0 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +# please keep this list sorted alphabetically +# diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..17fc5de --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,3 @@ +# List of source files containing translatable strings. + +