From b990aa019e5ad76d67dad578aaf4ae39797047e3 Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Mon, 24 Nov 2014 12:25:18 +0200 Subject: [PATCH] initial import 1.2 --- .gitignore | 39 + AUTHORS | 5 + COPYING | 3 + COPYING.LGPL3 | 166 ++++ ChangeLog | 10 + INSTALL | 370 ++++++++ Makefile.am | 32 + NEWS | 1 + README | 1 + autogen.sh | 157 ++++ configure.ac | 42 + debian/README.Debian | 6 + debian/README.source | 9 + debian/changelog | 5 + debian/compat | 1 + debian/control | 23 + debian/copyright | 38 + debian/docs | 2 + debian/emacsen-install.ex | 47 ++ debian/emacsen-remove.ex | 15 + debian/emacsen-startup.ex | 27 + debian/init.d.ex | 154 ++++ debian/libsexpr-dev.dirs | 2 + debian/libsexpr-dev.install | 4 + debian/libsexpr.cron.d.ex | 4 + debian/libsexpr.default.ex | 10 + debian/libsexpr.dirs | 1 + debian/libsexpr.doc-base.EX | 20 + debian/libsexpr.install | 1 + debian/manpage.1.ex | 56 ++ debian/manpage.sgml.ex | 154 ++++ debian/manpage.xml.ex | 291 +++++++ debian/menu.ex | 2 + debian/postinst.ex | 39 + debian/postrm.ex | 37 + debian/preinst.ex | 35 + debian/prerm.ex | 38 + debian/rules | 13 + debian/shlibs.local.ex | 1 + debian/source/format | 1 + debian/watch.ex | 23 + doc/TODO | 0 examples/TODO | 0 include/Makefile.am | 2 + include/sexpr/cstring.h | 146 ++++ include/sexpr/faststack.h | 157 ++++ include/sexpr/sexp.h | 771 +++++++++++++++++ include/sexpr/sexp_errors.h | 139 ++++ include/sexpr/sexp_memory.h | 165 ++++ include/sexpr/sexp_ops.h | 138 +++ include/sexpr/sexp_vis.h | 69 ++ lib/Makefile.am | 34 + lib/cstring.c | 225 +++++ lib/event_temp.c | 896 ++++++++++++++++++++ lib/faststack.c | 228 +++++ lib/io.c | 140 ++++ lib/libsexpr-1.2.pc.in | 13 + lib/parser.c | 1573 +++++++++++++++++++++++++++++++++++ lib/sexp.c | 546 ++++++++++++ lib/sexp_memory.c | 132 +++ lib/sexp_ops.c | 230 +++++ lib/sexp_vis.c | 130 +++ po/ChangeLog | 0 po/LINGUAS | 2 + po/POTFILES.in | 3 + 65 files changed, 7624 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING.LGPL3 create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 debian/README.Debian create mode 100644 debian/README.source create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100644 debian/emacsen-install.ex create mode 100644 debian/emacsen-remove.ex create mode 100644 debian/emacsen-startup.ex create mode 100644 debian/init.d.ex create mode 100644 debian/libsexpr-dev.dirs create mode 100644 debian/libsexpr-dev.install create mode 100644 debian/libsexpr.cron.d.ex create mode 100644 debian/libsexpr.default.ex create mode 100644 debian/libsexpr.dirs create mode 100644 debian/libsexpr.doc-base.EX create mode 100644 debian/libsexpr.install create mode 100644 debian/manpage.1.ex create mode 100644 debian/manpage.sgml.ex create mode 100644 debian/manpage.xml.ex create mode 100644 debian/menu.ex create mode 100644 debian/postinst.ex create mode 100644 debian/postrm.ex create mode 100644 debian/preinst.ex create mode 100644 debian/prerm.ex create mode 100755 debian/rules create mode 100644 debian/shlibs.local.ex create mode 100644 debian/source/format create mode 100644 debian/watch.ex create mode 100644 doc/TODO create mode 100644 examples/TODO create mode 100644 include/Makefile.am create mode 100644 include/sexpr/cstring.h create mode 100644 include/sexpr/faststack.h create mode 100644 include/sexpr/sexp.h create mode 100644 include/sexpr/sexp_errors.h create mode 100644 include/sexpr/sexp_memory.h create mode 100644 include/sexpr/sexp_ops.h create mode 100644 include/sexpr/sexp_vis.h create mode 100644 lib/Makefile.am create mode 100644 lib/cstring.c create mode 100644 lib/event_temp.c create mode 100644 lib/faststack.c create mode 100644 lib/io.c create mode 100644 lib/libsexpr-1.2.pc.in create mode 100644 lib/parser.c create mode 100644 lib/sexp.c create mode 100644 lib/sexp_memory.c create mode 100644 lib/sexp_ops.c create mode 100644 lib/sexp_vis.c create mode 100644 po/ChangeLog create mode 100644 po/LINGUAS create mode 100644 po/POTFILES.in 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. + +